Thursday, September 13, 2007

Tip#3: Extend your mocking framework

Currently I am using NMock2 in my C# development. I have however made a few extensions to allow me to test some edge cases. Due to the clean design of NMock extending it is really easy.

IAction


A normal use of NMock looks like this:

Expect.Once.On(someObject).Method("methodName").WithAnyArguments().Will(Return.Value("value"));


In this statement the 'Return.Value' method returns an object that implements the IAction interface. The job of this object is to perform some action at the point the expectation matches. In this example the effect is to set the return value of the method to a known string.

However... any class implementing the IAction interface can be passed to the 'Will' method, so if you have some special need to execute code at the point the method is matched, then here is a great place to put it.

Here is an example...
[Test]
public void Move_Sleeps_UntilUpdatedWithTrue
{
Expect.Once.On(sleeper).Method("Sleep").Will(Execute.Delegate(delegate { mono.Update(false); }));
Expect.Once.On(sleeper).Method("Sleep").Will(Execute.Delegate(delegate { mono.Update(false); }));
Expect.Once.On(sleeper).Method("Sleep").Will(Execute.Delegate(delegate { mono.Update(true); }));
mono.Move(120);
}


Here I have used an IAction class that invokes a delegate at the point your expectation is met. In this case I am using it to test a piece of code that repeatedly sleeps (using a sleeper service) until the object is updated with true. I am intercepting the call to sleep and instead taking the opportunity to update the object.

Here is the code that makes that possible.
public class Execute : IAction
{
public delegate void DelegateAction();
private readonly DelegateAction action;

public static IAction Delegate(DelegateAction action)
{return new Execute(action);}

private Execute(DelegateAction action)
{this.action = action;}

public void Invoke(Invocation invocation)
{action();}

public void DescribeTo(TextWriter writer)
{}
}
So in way of explanation: the invoke method is want gets called when the expectation is met. It just invokes the delegate the 'Execute' object was constructed with. The rest is just static methods to allow you to say Execute.Delegate(...) rather than new Execute(...)

Next post I'll explain how I test firing events using another extension to NMock.

Wednesday, September 05, 2007

Installing simple_helpful without edge Rails

DHH has helpfully moved the simply_helpful Ruby on Rails plugin.
If you are not running edge you can still install, you just have to use:

script/plugin install http://dev.rubyonrails.org/svn/rails/plugins/legacy/simply_helpful/

Tuesday, August 14, 2007

Tip:#2 Smell: Duplicate Tests Indicate a Missing Class

Smell: A class with two public methods on it, both perform the same functionality, or one is a subset of the other. The existence of a private method is a good indication of this.

To fully test these public methods you have to repeat a bunch of tests. There has to be a lazier simpler solution.

Recently I have been getting this smell a lot using MVC in a .Net winforms app.

.Net forms are hard to unit test. It is therefore helpful to keep your Views as thin as possible. Just use them to expose the form fields as a bunch of properties and to catch events and call the corresponding method on the controller. This moves the logic to the Controller where it is far more testable.

This can however lead to methods on the controller like "OnStartButtonClicked" and "OnStartMenuItemSelected". Both are going to perform the same actions. Both are going to need the same set of tests.

The solution is simple. Use the 'Extract Class' refactoring to pull the private method out to another class and use Dependency Injection to pass an instance of this new class back to the original class.

Following this above advice though you end up with another object. In my experience this split makes a lot of sense. I call this new class a Service. I rename the new thinner Controller to Presenter which better resembles it's remaining responsibilities.

(Note: I've read a few things on the differences between MVC and MVP, but I don't really get it. What I have here may be what is meant by the naming. Either way I like this design better.)

I'm really liking the new code. The view is really thin. The presenter translates UI events to service calls, and knows which views to update when the domain changes.

A piece of advice Steve Hayes often gives is "Design your UI layer so you could replace it with a command line and everything would keep working". I have struggled to do this with .Net, even with MVC. Having this new split however I can see keeping the Service and Model layers and replacing the UI would be easy.

So... Look out for duplicates tests... get lazy and write better code!

Friday, July 06, 2007

Tip:#1 Testing Events in C#

If you have a class that causes a .Net event to fire. When writing a test for the event, you can add a handler to the event that sets a flag that you then assert on in your code. Using normal delegates means the variable would need to be a class member and get initialized in Setup. Use of anonymous delegates cleans this up nicely.

[Test]
public void TriggerEvent_CausesEventThatFiresToFire()
{
Customer customer = new Customer("Ben");
string changedPropertyName = null;

customer.PropertyChanged += delegate(object sender, PropertyChangedEventArgs args)
{changedPropertyName = args.PropertyName;};

customer.Name = "Kate";

Assert.AreEqual("Kate",changedPropertyName);
}

Thursday, June 28, 2007

Design for unit testing

Object oriented languages allow lots of ways to solve the same problem. As you get better at design you see some designs as good [loose coupling, high cohesion]. You can view your design skills as a set of filters you use to choose which design to pick.

Doing TDD leads you to learning some new filters. If a design is not testable it is not a valid design. I want to write an article on this.. but for now check this out: http://www.codeproject.com/useritems/DesignPatternsForUnitTest.asp

GitHub Projects