c# - 使用 Mocks 验证依赖调用时的 TDD Arrange Act Assert 模式

标签 c# unit-testing tdd moq arrange-act-assert

我正在使用 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
    // ...?
}

最佳答案

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

  • 提供信息或数据
  • 做一份工作

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

当 mock 正在执行一项工作时,委托(delegate)可以被验证。这就是您拥有断言的原因。

您在严格交互中所做的是确保每一次交互都符合预期,基本上就是说,“这是我期望发生的事情,如果发生任何其他事情,那就是错误的。”这是对 Act、Arrange、Assert 的一种不同类型的测试,它说,“在这种情况下,当我做这些事情时,我应该得到这个结果。”

有了一个“不错”的模拟,您只需要担心您感兴趣的交互。因此,例如,如果我是一名 Controller 并且我正在一个存储库中查找一些信息,并使用一个验证器,然后将结果保存在另一个存储库中,我可能有几个测试:

  • 检查我是否根据正确的信息进行验证
  • 检查我如何回应不正确的验证
  • 还有一个检查我是否保存了该项目。

对于严格的模拟,您必须执行所有 期望,即使您只对“保存”感兴趣。通过使用一个很好的模拟,我们可以拆分行为的不同方面,并且在每个测试中只关注其中一个方面。

作为额外的奖励,漂亮的模拟允许你做:

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

而严格的模拟会让你这样做:

  • 给定上下文
  • 期待一些事情发生
  • 当我执行一个事件时
  • 然后返回并阅读实际结果。

通常认为第一个更具可读性。

关于c# - 使用 Mocks 验证依赖调用时的 TDD Arrange Act Assert 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8606816/

相关文章:

python - PyUnit 中是否弃用了测试套件?

c# - 如何在不克隆的情况下列出远程存储库中的文件?

c# - 发生传输层错误

python - 单元测试 : Does it make sense to test parent object methods?

tdd - 是否有任何示例,资源或什至由Asp.net MVP + SandcaSTLe + TDD/Nunit + Fitnesse组成的框架?

ruby-on-rails - 集成测试 : create vs new in controller

reactjs - 我应该测试相反的情况吗?

c# - 如何将 Timespan 对象格式化为字符串

c# - View 必须派生自 WebViewPage

python - 告诉 f2py 跳过一个函数