Given the following code
public class Entity { public string Name { get; set; } public string Status { get; set; } } public interface IRepository { void InsertEntity(Entity entity); void UpdateEntity(Entity entity); } public class Processor { private IRepository _repository; public Processor(IRepository repository) { _repository = repository; } public void Execute(string name) { var entity = new Entity() { Name = name, Status = "Initialized" }; _repository.InsertEntity(entity);
I can write unit test to check if the repository is called inside the Execute method, storing the value of the object using the InsertEntity method. In other words, I would like to make sure that when I call the InsertEntity method, the value of the Status property of the Initialized object. So my unit test will be like this:
[TestMethod] public void ShouldSaveEntityWithStatusInitialized() { var mock = new Mock<IRepository>(); var processor = new Processor(mock.Object); processor.Execute("test"); mock.Verify(m => m.InsertEntity(It.Is<Entity>(e => e.Status == "Initialized")), Times.Once());
However, this code does not work even when calling the InsertEntity method with Status = "Initialized" (I debugged this). I think this is because the entity object changes during the execution of the Execute method (at the end, the Status property changes to "Processed"), and Moq checks the call against the changed object. In fact, this other unit test works well.
[TestMethod] public void ShouldUpdateEntityWithStatusProcessedAtTheEnd() { var mock = new Mock<IRepository>(); var processor = new Processor(mock.Object); processor.Execute("test"); mock.Verify(m => m.InsertEntity(It.Is<Entity>(e => e.Status == "Processed")), Times.Once()); }
The only way I found to do my first unit test works is to use the following workaround. I save the value of the Status property using the Moq callback function and state that later.
[TestMethod] public void ShouldSaveEntityWithStatusInitialized_withWorkaround() { var mock = new Mock<IRepository>(); var processor = new Processor(mock.Object); string status = string.Empty; mock.Setup(m => m.InsertEntity(It.IsAny<Entity>())).Callback((Entity e) => status = e.Status); processor.Execute("test"); Assert.AreEqual("Initialized", status); }
But I didn’t like it. I would like to know if there is a way to make Moq check the calls made in the mock object during the execution of the STU (test system), and not after the entire execution has been completed.
thanks