Business owner must choose the first stories to be developed in the first iteration.
“A user should be able to add a new type of item to the application”
Features:
- An item type entity and a persistence layer
- An item type domain service that can provide a list of item types in the data store
- A user interface to enable business users to list existing item types and create new ones
Inside out / outside in… we are doing the former ie starting with the Repository layer.
http://nbehave.codeplex.com/releases/view/68223
Code Snippet
public class when_working_with_the_item_type_repository : Specification {
}
public class and_saving_a_valid_item_type : when_working_with_the_item_type_repository {
private int _result;
private IItemTypeRepository _itemTypeRepository;
private ItemType _testItemType;
private int _itemTypeId;
protected override void Because_of() {
_result = _itemTypeRepository.Save(_testItemType);
}
protected override void Establish_context() {
base.Establish_context();
var randomNumberGenerator = new Random();
_itemTypeId = randomNumberGenerator.Next(32000);
// making a mock ISessionFactory
// which just returns the random number
// when an ItemType is passed in and saved
var sessionFactory = new Mock<ISessionFactory>();
var session = new Mock<ISession>();
session.Setup(s => s.Save(_testItemType))
.Returns(_itemTypeId);
sessionFactory.Setup(sf => sf.OpenSession())
.Returns(session.Object);
// injecting in our mock sessionFactory
_itemTypeRepository = new ItemTypeRepository(sessionFactory.Object);
}
[Test]
public void then_a_valid_item_type_id_should_be_returned() {
_result.ShouldEqual(_itemTypeId);
}
}
Specification inherits off SpecBase which is NBehave.Spec.Nunit. So basically Nunit with BDD style sugar.
Using Moq to Mock out the ORM (Fluent NHibernate).
Code Snippet
public interface IItemTypeRepository {
int Save(ItemType _testItemType);
}
public class ItemTypeRepository : IItemTypeRepository {
private ISessionFactory _sessionFactory;
public ItemTypeRepository(ISessionFactory sessionFactory) {
_sessionFactory = sessionFactory;
}
public int Save(ItemType itemType) {
int id;
using (var session = _sessionFactory.OpenSession()) {
id = (int)session.Save(itemType);
session.Flush();
}
return id;
}
}
Second test and Refactoring
Code Snippet
public class when_working_with_the_item_type_repository : Specification {
protected IItemTypeRepository _itemTypeRepository;
protected Mock<ISessionFactory> _sessionFactory;
// protected so can restub in each test the required behaviour
protected Mock<ISession> _session;
protected override void Establish_context() {
base.Establish_context();
// Mock out FNH
_sessionFactory = new Mock<ISessionFactory>();
_session = new Mock<ISession>();
_sessionFactory.Setup(sf => sf.OpenSession())
.Returns(_session.Object);
_itemTypeRepository = new ItemTypeRepository(_sessionFactory.Object);
}
}
// second test
public class and_saving_an_invalid_item_type : when_working_with_the_item_type_repository {
private Exception _result;
protected override void Because_of() {
try {
_itemTypeRepository.Save(null);
}
catch (Exception exception) {
_result = exception;
}
}
protected override void Establish_context() {
base.Establish_context();
// the mock knows that when a null is passed
// instead of an ItemType then throw ArgumentNullException
_session.Setup(s => s.Save(null))
.Throws(new ArgumentNullException());
}
[Test]
public void then_an_argument_null_exception_should_be_raised() {
_result.ShouldBeInstanceOfType(typeof(ArgumentNullException));
}
}
// first test
public class and_saving_a_valid_item_type : when_working_with_the_item_type_repository {
private int _result;
private ItemType _testItemType;
private int _itemTypeId;
protected override void Because_of() {
_result = _itemTypeRepository.Save(_testItemType);
}
protected override void Establish_context() {
base.Establish_context();
var randomNumberGenerator = new Random();
_itemTypeId = randomNumberGenerator.Next(32000);
// when passed an ItemType, return the random number
_session.Setup(s => s.Save(_testItemType))
.Returns(_itemTypeId);
}
[Test]
public void then_a_valid_item_type_id_should_be_returned() {
_result.ShouldEqual(_itemTypeId);
}
}
Now have 2 unit tests.. which are testing the repository
- Saving a valid item type returns newly created id
- Saving an invalid item type throws an ArgumentNullException
The repository is being tested using Mocks of the FNH Save method. Because we’re using FNH’s interfaces it should just work (after putting in config files and creating the DB!).