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

fea*_*net 10 c# tdd unit-testing moq arrange-act-assert

Moq用来测试一些void方法的行为.使用MockBehaviour.Strict的模拟必须在指定每个呼叫Arrange一步.这导致许多测试没有任何Assert(或验证)步骤.通过条件只是测试运行而没有抛出异常.我错过了什么吗?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
    // ...?
}
Run Code Online (Sandbox Code Playgroud)

Lun*_*ore 24

你的模拟取代了合作者.理想情况下,它可以做以下两件事之一:

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

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

当模拟器正在完成工作时,可以验证委派.这就是你有Assert的原因.

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

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

  • 一个检查我是否正在验证正确的信息
  • 一个检查我是如何回应不正确的验证
  • 和一个检查我保存该项目.

通过严格的模拟,你必须做所有的期望,即使你感兴趣的只是"保存".通过使用一个漂亮的模拟,我们可以分解行为的不同方面,并且只关注每个测试中的一个.

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

  • 给定一个背景
  • 当这个事件发生时
  • 然后应该发生这种结果

严格的模拟让你做到:

  • 给定一个背景
  • 期待一些事情发生
  • 当我举办活动时
  • 然后回去看看结果本来应该是什么.

其中第一个通常被认为更具可读性.

  • 是的,这就是我所倡导的(这就是为什么像Moq这样的"好"的模拟框架被创造出来的原因).请注意,您仍然需要设置任何提供信息的模拟 - 但最棒的是您现在可以执行此操作*无论是否被调用*. (2认同)