software development

Testing my simple unit of work implementation

Testing my simple unit of work implementation

My previous post describes the design of my simple unit of work implementation. I was quite happy with this design until I tried testing classes that use the implementation. This is a major obstacle because I’m a firm believer in unit testing and TDD. This post details the evolution of design of the unit of work implementation to allow for testability while maintaining low-friction consumption.

The last post left us with this solution:

https://gist.github.com/1745709/9afa9b9df14a72a449a0cfade2c66c854ef95675

 

public interface IDependency { void SomeMethod(string s); } public class MyClass { private readonly IDependency dependency; private readonly Func startNewUnitOfWork;  public MyClass(IDependency dependency, Func startNewUnitOfWork) { this.dependency = dependency; this.startNewUnitOfWork = startNewUnitOfWork; }  public void DoWork() { using (var uow = startNewUnitOfWork()) { uow.Begin(() => dependency.SomeMethod("hi")); } } } public interface IUnitOfWork : IDisposable { void Begin(); void Commit(); void RollBack();  void Begin(Action action); } //Implementation public class UnitOfWork : IUnitOfWork { private readonly ISessionFactory sessionFactory; private ISession currentSession; private ITransaction currentTransaction;  public UnitOfWork(ISessionFactory sessionFactory) { this.sessionFactory = sessionFactory; }  public void Begin() { currentSession = sessionFactory.OpenSession(); CurrentSessionContext.Bind(currentSession); currentTransaction = currentSession.BeginTransaction(); }  public void Commit() { currentTransaction.Commit(); CurrentSessionContext.Unbind(sessionFactory); }  public void RollBack() { currentTransaction.Rollback(); CurrentSessionContext.Unbind(sessionFactory); }  public void Dispose() { currentTransaction.Dispose(); currentSession.Dispose(); }  public void Begin(Action action) { try { Begin(); action.Invoke(); Commit(); } catch (Exception ex) { RollBack(); throw ex; } } }

 

When testing DoWork(), the primary goal is to test that dependency.SomeMethod is called with the correct methods. I’d also like to test whether uow.Begin(), uow.Commit (or uow.Rollback if appropriate) and uow.Dispose() are called. (Ideally I’d also like to test the order in which these methods are called but support for ordering was removed from Rhino Mocks 3.5).

My first pass at a test for MyClass is shown as MyClassTest below:

https://gist.github.com/1745709/5ba6187839928d50d2ce625011194e2be1c7f7aa

 

[Test] public void TestDoWork() { var dependency = MockRepository.GenerateMock(); dependency.Expect(d => d.SomeMethod("hi"));  var uow = MockRepository.GenerateMock();  var uowProvider = MockRepository.GenerateMock>(); uowProvider.Expect(u => u.Invoke());  var sut = new MyClass(dependency, uowProvider); sut.DoWork();  uowProvider.VerifyAllExpectations(); uow.VerifyAllExpectations(); }

 

There are however several issues with this approach:

  • There is no expectation that uow.Begin is called (or any other methods of uow
  • The expectation on IDependency.SomeMethod() will fail. IUnitOfWork is being mocked, so even when uow.Begin() is called, it is the methd of the mock proxy that is callsed, and not the real Begin(). Therefore the line action.Invoke() in UnitOfWork will never be called.

In actual fact, with this design of UnitOfWork, we cannot set any expectations or assertions on IDependency. We can only set expectations on the calls made by our system under test. In this case, it is the call made to IUnitOfWork.Begin(Action action).

The test should therefore change to the one shown here:

https://gist.github.com/1745709/3375a9dbe9ae9e3c93212364f5c51ca1354c80c1

 

[Test] public void TestDoWork() { var dependency = MockRepository.GenerateMock(); Action expectedAction = () => dependency.SomeMethod("hi");  var uow = MockRepository.GenerateMock(); uow.Expect(u => u.Begin(Arg.Matches(actual => DelegatesEqual(expectedAction, actual))));  var uowProvider = MockRepository.GenerateMock>(); uowProvider.Expect(u => u.Invoke()) .Return(uow);  var sut = new MyClass(dependency, uowProvider); sut.DoWork();  uowProvider.VerifyAllExpectations(); uow.VerifyAllExpectations(); } private bool DelegatesEqual(Action expected, Action actual) { if (expected.Target != actual.Target) return false;  var firstMethodBody = expected.Method.GetMethodBody().GetILAsByteArray(); var secondMethodBody = actual.Method.GetMethodBody().GetILAsByteArray();  if (firstMethodBody.Length != secondMethodBody.Length) return false;  for (var i = 0; i < firstMethodBody.Length; i++) { if (firstMethodBody[i] != secondMethodBody[i]) return false; } return true; }

 

I.e., we’re setting an expectation on the Action passed into IUnitOfWork.Begin() (as well as expecting that method to be called).

This looks a lot better and makes a lot more sense. However, the test fails. It took me a little while to understand why. It fails, because the Action is represented by a lambda/closure.

Something strange happens to the delegate when the closure is closed over. If you debugs the test code above, and inspect the expected and actual delegates, you’ll find that their Method and Target properties are different. I’ve used the method from this StackOverflow answer to compare delegates for equality.) The expected delegate is associated with the test class. The actual delegate (created in UnitOfWork) refers to the UnitOfWork class. Neither of them refer to IDependency.SomeMethod, even though both are instantiated by () => IDependency.SomeMethod. Therefore this way of testing is not feasible.

What’s required is a way to compare delegates without worrying about the closures being closed over in strange ways. However it would be nice to retain the elegant way of using IUnitOfWork.Begin() with a delegate.

I managed to achieve this by changing IUnitOfWork.Begin() so that instead of taking an Action it takes an Action. The changed unit of work and calling code change to:

//Test: [Test]

public void TestDoWork() { var dependency = MockRepository.GenerateMock(); Action expectedAction = dependency.SomeMethod;  var uow = MockRepository.GenerateMock(); uow.Expect(u => u.Begin( Arg>.Matches(actual => DelegatesEqual(actual, expectedAction)), Arg.Matches(actual => actual == "hi"))); uow.Expect(u => u.Dispose()); //As before }

//MyClass.DoWork(): public void DoWork()

{ using (var uow = startNewUnitOfWork()) { uow.Begin(dependency.SomeMethod, "hi"); } }

//IUnitOfWork:

public interface IUnitOfWork : IDisposable { //As before void Begin(Action action, T t); }

//New method on UnitOfWork:

public void Begin(Action action, T t) { try { Begin(); action.Invoke(t); Commit(); } catch (Exception ex) { RollBack(); throw ex; } }

 

https://gist.github.com/1745709/81f15d8a0e473a757f74dd1c2fcc698e8fffea6a

We can now specify the delegate without using lambdas, and incurring funny closure behaviour. This test now works as expected, and we can test everything we wanted to. The only concession is instead of using IUnitOfWork.Begin(() => dependency.SomeMethod(“hi”)); we now use IUnitOfWork.Begin(dependency.SomeMethod, “hi”); which is maybe a little less intuitive to read. In my opinion this is a reasonable trade-off to increase testability of the solution.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s