TDD在使用mock验证依赖项调用时安排行为断言模式

本文关键字:模式 断言 调用 mock 依赖 验证 TDD | 更新日期: 2023-09-27 18:18:33

我使用Moq来测试一些void方法的行为。使用MockBehaviour.Strict时,必须在Arrange步骤中指定对模拟的每个调用。这导致许多测试没有任何Assert(或Verify)步骤。通过条件简单地说就是测试运行时没有抛出异常。我错过什么了吗?Arrange, Act, Assert模式在使用严格模拟时是否不合适?是否有更语义化的方式来布局这些测试?

一个简单的例子…

[TestClass]
public void DeleteUser_ShouldCallDeleteOnRepository()
{
    // Arrange
    var userRepository = new Mock<IUserRepository>(MockBehavior.Strict);
    int userId = 9;
    userRepository.Setup(x => x.Delete(userId));
    var controller = new UserController(userRepository.Object);
    // Act
    controller.DeleteUser(userId);
    // Assert
    // ...?
}

TDD在使用mock验证依赖项调用时安排行为断言模式

您的mock正在取代协作者。理想情况下,它会做以下两件事之一:

  • 提供信息或数据
  • 正在工作

当mock提供信息或数据时,它应该是一个存根就足够了。您可以将模拟的返回值设置为所需的信息。这应该是Arrange的一部分。

当模拟执行任务时,可以验证委托。这就是为什么要使用Assert

对于严格交互,你所做的是确保每一个交互都是预期的,基本上说,"这是我期望发生的,如果发生了其他任何事情,那就是错误的。"这是Act, Arrange, Assert的另一种测试,它说的是,"在这个上下文中,当我做这个事情时,我应该得到这个结果。"

使用一个"漂亮"的mock,您只需要担心您感兴趣的交互。因此,例如,如果我是一个控制器,我在一个存储库中查找一些信息,用验证器验证它,然后将结果保存在另一个存储库中,我可能有几个测试:

  • 一个来检查我是否根据正确的信息进行验证
  • 一个检查我如何响应不正确的验证
  • 和一个检查我保存项目。
对于严格模拟,您必须执行所有期望,即使您感兴趣的只是"保存"。通过使用一个好的模拟,我们可以将行为的不同方面分开,并且在每个测试中只关注其中一个方面。

作为额外的奖励,好的mock允许您做:

  • 给定上下文
  • 当此事件发生时
  • 那么这个结果应该会发生

而严格模拟让你做:

  • 给定上下文
  • 期待一些事情发生
  • 当我执行一个事件
  • 然后回过头来看看结果应该是什么。