【问题标题】:Can someone please clarify my understanding of a mock's Verify concept?有人可以澄清我对模拟验证概念的理解吗?
【发布时间】:2011-03-07 08:03:43
【问题描述】:

我正在玩一些单元测试和模拟。我正在尝试验证是否在我的方法中调用了某些代码。我认为我不理解嘲笑的 Verify 部分正确,因为我只能验证 main 方法.. 这很愚蠢,因为无论如何我 Act 就是这样。

我正在尝试测试我的逻辑是否正常工作 - 所以我想我使用验证来查看方法中的某些步骤是否已达到并实施。

让我们用这个例子来突出我做错了什么。

public interface IAuthenticationService
{
    bool Authenticate(string username, string password);
    SignOut();
}

public class FormsAuthenticationService : IAuthenticationService
{
    public bool Authenticate(string username, string password)
    {
        var user = _userService.FindSingle(x => x.UserName == username);
        if (user == null) return false;

        // Hash their password.
        var hashedPassword = EncodePassword(password, user.PasswordSalt);

        if (!hashedPassword.Equals(password, StringComparison.InvariantCulture))
            return false;

        FormsAuthentication.SetAuthCookie(userName, true);
        return true;
    }
}

所以现在,我想验证一下

  • EncodePassword 被调用。
  • FormsAuthentication.SetAuthCookie(..) 被调用。

现在,我不在乎这两者的含义。更重要的是,我不想测试这些方法。这必须在其他地方处理。我应该做的是验证这些方法是否被调用并且..如果可能的话......返回了预期的结果。

这是对模拟中“验证”含义的正确理解吗?

如果是这样,有人可以告诉我如何做到这一点。更喜欢moq,但我对任何事情都很满意。

【问题讨论】:

    标签: .net asp.net mocking moq rhino-mocks


    【解决方案1】:

    您通常应该(至少在 IMO)模拟依赖项,而不是在被测试的类中模拟其他方法。例如,您可以有一个用于EncodePassword 调用的IPasswordEncoder 接口。您可以模拟 那个,并验证该方法是否已被调用...但在同一个类中它没有多大意义。

    我敢说许多模拟框架可以做这种模拟,但我个人不鼓励这样做。如果您找到了希望能够注入不同功能的地方,请考虑将它们设为独立的依赖项。

    【讨论】:

      【解决方案2】:

      在我看来,你有两个问题:

      1. EncodePassword 属于FormsAuthenticationService,这使得它更难模拟。 这个问题有两种可能的解决方案:

        1. 将 EncodePassword 保护为虚拟,并创建 Mock<FormsAuthenticationService>。在这种情况下,您应该可以VerifyEncodePassword
        2. 将密码编码提取到不同的服务中,因为它与身份验证实现无关。
      2. FormsAuthentication.SetAuthCookie(..) 是一个静态方法。这里一个合理的解决方案是使用完全包装FormsAuthentication 的附加服务,但除此之外不做任何事情,因此您不必对其进行测试。

      【讨论】:

        【解决方案3】:

        在测试驱动开发中,您很少想要断言调用了私有方法。什么是验证 EncodePassword 被称为真正的测试?如果我们详细查看该方法,我们会看到,例如,我可以更改方法以丢弃EncodePassword 调用的结果而不会破坏测试。这肯定是不对的——测试变得太灵活了,用处不大。而是考虑这两种方法。

        测试类的公共接口

        这是您通常想要的。你真的关心这个方法是否被调用? Authenticate 方法做了一些事情,我们想测试这个方法是否做了它应该做的事情。也许像这样的断言来测试错误的密码不会进行身份验证:

        Assert.That(service.Authenticate("Pure.Krome", "wrong pass"), Is.False);
        

        这允许您在不破坏测试的情况下更轻松地重构类。测试的文档记录能力也增加了 - 这个类应该如何使用?

        将方法中的功能提取到它自己的类中

        有时不应在测试期间调用类的私有方法,而应进行模拟。例如,静态方法调用FormsAuthentication.SetAuthCookie(userName, true) 可能有副作用,或者当不在网络服务器上运行时可能会抛出。在这种情况下,我的经验是最好注入一个描述所需功能的接口。在这种情况下,例如带有 SetAuthCookie 方法的 ICookieTarget 可以被模拟。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-27
          • 1970-01-01
          • 2015-05-26
          • 1970-01-01
          • 2014-05-21
          • 2014-04-12
          相关资源
          最近更新 更多