给定以下代码
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);
// do other things with the entity
entity.Status = "Processed";
_repository.UpdateEntity(entity);
}
}
我可以编写一个单元测试来验证存储库是否在 Execute 方法中被调用,并使用方法 InsertEntity 保存实体的值。换句话说,我想确保在调用 InsertEntity 时,实体的 Status 属性的值是“Initialized”。所以我的单元测试是这样的:
[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()); // fail
}
但是,即使使用 Status = "Initialized" 调用 InsertEntity 方法,此代码也会失败(我已经调试过了)。我认为这是因为实体对象在 Execute 方法的执行过程中发生了变化(最后状态属性更改为“已处理”),并且 Moq 验证了对更改对象的调用。事实上,这个其他单元测试运行良好。
[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());
}
我发现使我的第一个单元测试有效的唯一方法是使用以下解决方法。我使用 Moq 的回调功能保存了 Status 属性的值,然后再断言。
[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);
}
但我不喜欢那样。我想知道是否有办法让 Moq在 STU(被测系统)执行期间验证对模拟对象的调用,而不是在所有执行完成之后。
谢谢