Thursday, July 16, 2009

BDD Specifications with Arrange Act Assert and Rhino Mocks 3.5

Programmers who have incorporated unit testing into their development process already know its advantages: cleaner code, courage to refactor, and higher speed. Writing tests is easy; it is writing good tests that makes automated unit testing a powerful tool. This article provides some basic information on using Rhino Mocks 3.5 to write unit test cases in the Arrange Act Assert pattern.

· Arrange - set up the unit under test

· Act - exercise the unit under test, capturing any resulting state

  • Assert - verify the behavior through assertions

I have two main base classes in this sample that handles the functionality of Mocking and AAA.

The base repository class contains the mock creating methods

public class BaseRepository

{

public MockRepository MockRepository = new MockRepository();

public TMock Mock() where TMock : class

{

return MockRepository.StrictMock();

}

public TStub Stub() where TStub : class

{

return MockRepository.Stub();

}

protected IDisposable PlayBack

{

get { return MockRepository.Playback(); }

}

protected IDisposable Record

{

get { return MockRepository.Record(); }

}

protected IDisposable PlayBackOnly

{

get

{

using (Record) { }

return PlayBack;

}

}

}

The ArrangeActAssertTearDown class contains methods that implement the AAA pattern.

public abstract class ArrangeAssertActTearDown : BaseRepository where T : class, new()

{

public T SystemUnderTest { get; private set; }

[TestInitialize]

public void Initialize()

{

Arrange();

SystemUnderTest = CreateSUT();

Act();

}

[TestCleanup]

public virtual void BasicTearDown()

{

TearDown();

}

public abstract void Arrange();

public virtual T CreateSUT()

{

return new T();

}

public abstract void Act();

public abstract void TearDown();

}

Implementing the pattern and writing test cases is as simple as

[TestClass()]

public class When_Getting_All_Products_From_Store : ArrangeAssertActTearDown<ProductService>

{

private IProductRepository ___ProductRepository;

private IStoreRepository ___StoreRepository;

private Store ___Store;

private IEnumerable<Product> ___Products;

private long __StoreIntId = 3;

public override void Arrange()

{

___ProductRepository = Mock<IProductRepository>();

___StoreRepository = Mock<IStoreRepository>();

}

public override ProductService CreateSUT()

{

return new ProductService(___ProductRepository, ___StoreRepository);

}

public override void Act()

{

___Store = new Store();

___Products = new List<Product>();

using (Record)

{

SetupResult.For<Store>(___StoreRepository.FindBy(0))

.IgnoreArguments()

.Return(___Store);

SetupResult.For<IEnumerable<Product>>(___ProductRepository.GetAllProductsFor(null))

.IgnoreArguments()

.Return(___Products);

}

}

[TestMethod]

[ExpectedException(typeof(ArgumentException))]

public void Should_Throw_Argument_Exception_If_StoreId_Is_Greater_Than_100()

{

___StoreRepository.BackToRecord(BackToRecordOptions.All);

___ProductRepository.BackToRecord(BackToRecordOptions.All);

var __Target = new ProductService();

var __Result = __Target.GetAllProductsForStore(110);

}

[TestMethod]

public void Should_Return_A_List_Of_Records()

{

using (PlayBack)

{

var __Result = SystemUnderTest.GetAllProductsForStore(__StoreIntId);

Assert.AreEqual<IEnumerable<Product>>(__Result, ___Products);

}

}

public override void TearDown()

{

___ProductRepository = null;

___StoreRepository = null;

}

}

No comments: