Moq – 使用在执行测试期间更改的参数validation调用

给出以下代码

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); } } 

我可以编写一个unit testing来validation是否在Execute方法中调用了存储库,并使用InsertEntity方法保存实体的值。 换句话说,我想确保在调用InsertEntity时,实体的Status属性值为“Initialized”。 所以我的unit testing将是这样的:

 [TestMethod] public void ShouldSaveEntityWithStatusInitialized() { var mock = new Mock(); var processor = new Processor(mock.Object); processor.Execute("test"); mock.Verify(m => m.InsertEntity(It.Is(e => e.Status == "Initialized")), Times.Once()); // fail } 

但是,即使调用Status =“Initialized”的InsertEntity方法,此代码也会失败(我已调试过)。 我认为这是因为实体对象在Execute方法执行期间被更改(最后Status属性更改为“Processed”)并且Moqvalidation对更改对象的调用。 事实上,这个其他unit testing效果很好。

 [TestMethod] public void ShouldUpdateEntityWithStatusProcessedAtTheEnd() { var mock = new Mock(); var processor = new Processor(mock.Object); processor.Execute("test"); mock.Verify(m => m.InsertEntity(It.Is(e => e.Status == "Processed")), Times.Once()); } 

我发现进行第一次unit testing的唯一方法是使用以下解决方法。 我使用Moq的回调function保存Status属性的值,并在稍后断言。

 [TestMethod] public void ShouldSaveEntityWithStatusInitialized_withWorkaround() { var mock = new Mock(); var processor = new Processor(mock.Object); string status = string.Empty; mock.Setup(m => m.InsertEntity(It.IsAny())).Callback((Entity e) => status = e.Status); processor.Execute("test"); Assert.AreEqual("Initialized", status); } 

但我不喜欢那样。 我想知道是否有办法让Moqvalidation执行STU(被测系统) 期间对模拟对象的调用,而不是在所有执行完成之后。

谢谢

恕我直言,最后一种方法(你称之为“黑客”)是测试状态值的正确方法。 我更清楚的是,您要在此测试中validation的是,在调用InsertEntity方法时,状态设置为“已初始化”。

要与Verify一起使用的方法对于您正在测试的内容更加模糊。 您是否要确认是否已调用InsertEntity ,或者您是否要测试该参数是“已初始化”,还是两者都可能,我不知道。 如果你想测试两者,那么这实际上是两个不同的unit testing。

你也可以做以下……

 mock.Setup(m => m.InsertEntity(It.Is(e => e.Status == "Initialized"))); 

但我不喜欢这种方法,因为这意味着当状态不是“已初始化”的值时,生成的InsertEntity代码将运行而不是模拟。 更有可能unit testing仍然会失败,但unit testing返回的断言失败消息更加模糊(由于实际的InsertEntity方法中发生了某些事情,故障发生)。 回调准确说明了您在unit testing中测试的内容。

 [TestMethod] public void ShouldSaveEntityWithStatusInitialized() { // arrange var mock = new Mock(); mock.Setup(m => m.InsertEntity(It.Is(e => e.Status == "Initialized"))); var processor = new Processor(mock.Object); // act processor.Execute("test"); // assert mock.Verify(); }