Tuesday, September 30, 2008

Houston ALT.NET Geek Dinner - Thursday Oct 2nd

kiwi This Thursday we're meeting again, this time at a new venue!  We're going to try out Ziggy's Healthy Grill.  At first I wasn't too pumped about this place, but the reviews are great, so what the heck.  I'll try a bean-sprout shake with black beans and tofu.  (Actually they don't serve food like that, I don't think)

If you aren't familiar with ALT.NET, check out Dave Laribee's original post, then the ALT.NET Wiki, then the ALT.NET official site.  We're basically a bunch of pragmatic .NET developers getting together in the interest of getting better at what we do.  If you're interested, join the mailing list and come meet us for dinner & drinks!

This month we didn't decide on a topic, so I'll just throw a couple in the hat:

  • Project / Development Processes
  • Contributing to Open Source

When?

This Thursday, October 2nd at 6:30-8:30.  I realize this overlaps a little with the VP Debate, but come on... it will be all over the intarwebs when you get home.

Where?

Ziggy's Healthy Grill


View Larger Map

2202 W. Alabama
Houston, TX 77098-3404
(713) 527-8588

 

Hope to see you there!

Monday, September 29, 2008

Now you have no excuse not to know jQuery

I'm not the first person to report this, but Scott Guthrie recently announced that jQuery will ship with Visual Studio 10This is huge news.  When I talk to an audience about javascript, most people I talk to have never used a javascript library.  Now I'm excited to have the ability to talk at length about jQuery and not have people raise their eyebrows at me and tell me that they hate javascript.

Recently at the ASP Insiders Summit I asked how many people actually like coding in javascript.  About 6 people (out of 30) raised their hands.  I then asked, "How many of you use jQuery?"  The same 6 kept their hands in the air.  Postulate what you want, this can either mean:

jQuery makes you love javascript again.

or...

Those who love javascript, choose jQuery.

Though I won't laugh in your face, like some :), but I will gently suggest that if you aren't yet familiar with jQuery, now is the time to learn.  I can recommend jQuery in Action if you're serious about it, but a simple Google search will get you most of what you need.

The other reason why this is big news, is that soon you'll be able to open up product support issues with Microsoft about jQuery.  Let that sink in for a second.  An open source project, under the MIT license, will be fully supported by Microsoft.

I applaud Microsoft for making this decision.  It's not your typical Microsoft anymore.

Monday, September 15, 2008

Ike is Gone, We're Okay

Thanks to all who checked in with me during hurricane Ike.  My family and I are okay, and we're now in Dallas awaiting restoration of power.  During the storm I still had Edge connectivity on my iPhone, so I was checking local tweets with Twinkle, and it was very interesting to see what folks within 10 miles of me were saying.  What a cool feature. 

As for damage, our house is fine.  Luckily, all we lost was our fence!  Some houses weren't so lucky.

Here are some pics that I took with my phone:

Hurricane Ike 006Hurricane Ike 001Hurricane Ike 004Hurricane Ike 005     Hurricane Ike 009Hurricane IkeHurricane Ike 010Hurricane Ike 002

My wife took some pictures with a much better camera, so I'll link to those soon.  Time to clean up!

Wednesday, September 10, 2008

Using Extension Methods to Clean Up Tests

A lot of unit tests for ASP.NET MVC projects will look a lot like this:

[Test]
public void list_action_should_render_default_view()
{
	var controller = CreateProductController(); //defined elsewhere
	var result = controller.List();

	Assert.That(result, Is.TypeOf(typeof(ViewResult));
	var viewResult = (ViewResult)result;
	Assert.That(viewResult.ViewName, Is.EqualTo(string.Empty));
}

We basically create the controller, invoke the desired action, and verify that the result is of type ViewResult, and that the name of the view is an empty string. 

This test isn't necessarily all bad.  It is easy to read and consists of only 5 lines of code.  Here's another test, this time testing that an action redirects the user:

[Test]
public void login_action_should_redirect_to_home_index_on_successful_login()
{
	string username = "bob";
	string password = "pass123";

	var loginService = MockRepository.GenerateStub();
	loginService.Stub(x => x.Authenticate(username, password).Return(true);

	var controller = new AccountController(loginService);
	var result = controller.Login(username, password);

	Assert.That(result, Is.TypeOf(typeof(RedirectToRouteResult)));
	var redirectResult = (RedirectToRouteResult)result;
	Assert.That(result.RouteValues["controller"], Is.EqualTo("home"));
	Assert.That(result.RouteValues["action"], Is.EqualTo("index"));
}

Notice the duplication?  When the tests are all starting to look like this, your spidey-sense should be tingling.  The DRY principle (Don't Repeat Yourself) applies to your unit tests as well!

Let's see if we can do better.  I'm just going to type some code that I wish I had:

controller.List().ShouldRenderDefaultView();

That's a lot more concise!  It reads very well, and can easily eliminate 3-4 lines of repetitive test code.  With .NET 3.5, we were given Extension Methods.  If you aren't yet aware, extension methods allow us to bolt-on methods onto existing types.  In this case, we want to add a method to the return value of our List() action, which is ActionResult.

I created a static class called TestHelperExtensions.cs, and in it, placed our new method:

public static void ShouldRenderDefaultView(this ActionResult result)
{
	Assert.That(result, Is.TypeOf(ViewResult));
	Assert.That(((ViewResult)result).ViewName, Is.EqualTo(string.Empty));
}

That's it?  That was easy.  Let's extend this to support rendering a view of any name....

public static void ShouldRenderView(this ActionResult result, string viewName)
{
	Assert.That(result, Is.TypeOf(ViewResult));
	Assert.That(((ViewResult)result).ViewName, Is.EqualTo(viewName));
}

public static void ShouldRenderDefaultView(this ActionResult result)
{
	ShouldRenderView(result, string.Empty);
}

We can extend this idea further and capture the redirect family of asserts into another extension method:

controller.Login(username, password).ShouldRedirectTo("home", "index");

//we should also support custom route values
productController.Save(...).ShouldRedirectTo("products", "show").WithRouteValue("id", 5);

This can be implemented similarly...

//supports just passing in an action
public static RedirectToRouteResult ShouldRedirectTo(this ActionResult result, string action)
{
	return ShouldRedirectTo(result, null, action);
}

public static RedirectToRouteResult ShouldRedirectTo(this ActionResult result, string controller, string action)
{
	Assert.That(result, Is.TypeOf(typeof(RedirectToRouteResult)), "Should have redirected");
	var redirectResult = (RedirectToRouteResult) result;

	WithRouteValue(redirectResult, "Controller", controller);
	WithRouteValue(redirectResult, "Action", action);
           
	return redirectResult;
}

public static RedirectToRouteResult WithRouteValue(this RedirectToRouteResult result, string key, object value)
{
	Assert.That(result.Values[key], Is.EqualTo(value));
	return result;
}

This supports basic redirects with just an action, an action and a controller, and arbitrary route values that we need to test as well.

Leveraging simple extension methods to make your tests more concise and readable can really help reduce the overall weight of your tests (especially if you want to change behavior later).  This stands as an excellent reminder to write high-quality test code, just as you would for production code.

Tuesday, September 02, 2008

Meet Laribee This Friday in Houston

The title says it all folks.  David Laribee of Code Better and ALT.NET fame is in town.  Come meet us for drinks this Friday (September 5th) at 7pm.  We're going to meet up at Mi Luna for some Spanish tapas and string margaritas.  There will be plenty of geek-discussion & excellent food/drinks.

Mi Luna is in Rice Village.  Here's a map:


View Larger Map

 

If you're going to be there, let us know in the comments!