public void Add(Item item)
{
// set item created time
// set item updated time
repository.Add(item);
}
Moq provides some argument checking methods that we can use; there are:
- It.Is<Type>(...) ,
- It.IsInRange<Type>(...) and
- It.IsRegex(...)
Below is a unit test using one of the methods; It.Is<Type>(o => checking_condition)
[Fact]
public void Created_time_should_be_set_as_current_time()
{
// Arrange
var item = new Item();
var timeToCompare = DateTime.Now.AddHours(-1);
// Act
itemDS.Add(item);
// Assert
repository.Verify(c => c.Add(It.Is<Item>(i => i.CreatedAt.CompareTo(timeToCompare) > 0)));
}
or we can write like this:[Fact]
public void Created_time_should_be_set_as_current_time()
{
// Arrange
var item = new Item();
var timeToCompare = DateTime.Now.AddHours(-1);
repository.Setup(c => c.Add(It.Is<Item>(i => i.CreatedAt.CompareTo(timeToCompare) > 0)));
// Act
itemDS.Add(item);
// Assert
repository.VerifyAll();
}
Run the test. It will fail. Then we can put the code item.CreatedAt = DateTime.Now; on the method. Run the test again. It should pass now.Now we want to create a test to make sure updated time is set. We will use another way to check the parameter passed to a method. We will use Callback feature to retrieve the parameter. We cannot put a checking conditional logic in Callback argument. However we can assign the passed parameter to an existing object or add it to an existing collection then later we can inspect it.
[Fact]
public void Updated_time_should_be_set_as_current_time()
{
// Arrange
var item = new Item();
var timeToCompare = DateTime.Now.AddHours(-1);
// repository.Setup(c => c.Add(It.Is<Item>(i => i.UpdatedAt.CompareTo(timeToCompare) > 0)));
// alternate way by using Callback
repository.Setup(c => c.Add(It.IsAny<Item>())).Callback<Item>(i => item = i);
// Act
itemDS.Add(item);
// Assert
// repository.VerifyAll();
// now we are using Callback
Assert.True(item.UpdatedAt.CompareTo(timeToCompare) > 0);
}
Just for a note, if required, Callback can be combined with Returns function as well. For example:
mock.Setup(. . .)
.Returns(. . .)
.Callback(. . .)
mock.Setup(. . .)
.Callback(. . .)
.Returns(. . .)
.Callback(. . .)
Run the test. It will fail. Put the code item.UpdatedAt = DateTime.Now; Now the test will pass.
Our updated method now is
public void Add(Item item)
{
// set item created time
item.CreatedAt = DateTime.Now;
// set item updated time
item.UpdatedAt = DateTime.Now;
repository.Add(item);
}
References:
http://code.google.com/p/moq/wiki/QuickStart
http://stackoverflow.com/questions/3269717/moq-how-to-get-to-a-parameter-passed-to-a-method-of-a-mocked-service
