我可以模拟一个私有方法,或者测试这个POST方法的正确方法是什么



我有一个现有的ASP。. NET MVC应用程序,并想创建一些单元测试,我很快就遇到了下面的问题。是否有某种方法可以使用最小起订量,并说"当私有方法GETCLIENTIP运行时,然后返回xxx")?

因为现在它使用了HttpContext的部分,当然单元测试没有。

public HttpResponseMessage Post([FromBody]TriageCase TriageCase)
{
    if (ModelState.IsValid)
    {
        //Get the IP address from the request
        TriageCase.ipAddress = this.GetClientIP(Request);
        _log.Info("IP Address = " + TriageCase.ipAddress);
    }
}
public void Verify_Not_A_Suicide()
{
    TriageCaseRepository repository = new TriageCaseRepository();
    var controller = new TriageCasesController(repository);
    //This will not work because I must mock a private method in the controller?
    HttpResponseMessage result = controller.Post(new TriageCase());
}

有几种方法可以做到这一点,从令人讨厌的复杂方法到简单的折衷的方法。以下是一些:

  • 可以使GetClientIP方法对HttpContext不可知。然后把它变成内部的。控制器装配用InternalsVisibleTo标记,并放置单元测试装配路径。

使HttpContext的方法不可知可以使您避免使用HttpContextBase(3.5以后的抽象http上下文类,用于启用测试)并提供mock等(顺便说一句,您应该考虑一下)。特别是对于MVC)将特定字符串作为参数传递给方法。例如:特定的服务器变量字符串。

  • 你可以让GetClientIP方法接收HttpContextBase作为参数,然后使其内部。用InternalsVisibleTo标记控制器组件,并放置单元测试组件路径。

在你的控制器动作中,你需要调用this.GetClientIP(new HttpContextWrapper(HttpContext.Current))

这个方法

您的单元测试可以设置可模拟的上下文。更重要的是,您可以在上下文中设置期望,以确定是否调用了Request属性,或者是否进行了与ip地址相关的服务器变量调用。(更不用说直接的IP地址值验证了)

  • 你可以使用FakeItEasy或Microsoft mole等来为私有方法创建私有访问器。我通常不会那样做。

  • 你可以写一个基于INetworkUtility的接口,它有一个方法来给你IP地址。你的控制器可以使用这个接口。

  • 你可以有一个公共助手类来获取ip地址,它可以进行单元测试。

正如你所看到的,每个解决方案都有一些你需要做的权衡。

从Request对象获取IP地址是一个独立的逻辑,无论mvc或web api或asp web表单。(仍然是web特定的)所以把它作为辅助方法或基于接口的辅助方法是无害的。

就我个人而言,我更喜欢内部方法,(因为它几乎是私有的)并且不需要太多的代码更改。

在适当的TDD方式中,您不会对"私有"或"内部"方法进行单元测试。在单元测试中只使用公共接口。如果你对私有/内部方法进行单元测试,那么你就把单元测试与特定的实现捆绑得太紧了。

应该做的是使用依赖注入来注入实现单元测试所需的"依赖"功能的类/接口。这将有助于进一步模块化您的代码,从而使其更容易维护。

一般不要尝试测试私有方法。它只是变得混乱-测试一个动作的输入和输出…

要么做依赖注入的事情,要么考虑一个"test double"或"accessor"类…

对于测试双 -使private方法为protected,然后您继承控制器并根据需要手动模拟输入或输出。我并不是说这比Ioc好还是差,我是说这是另一种方式。

protected virtual string ExecuteIpnResponse(string url)
{
  var ipnClient = new WebClient();
  var ipnResponse = ipnClient.DownloadString(url);
  return ipnResponse;
}

我最近写了一篇关于这种测试风格的文章来检查paypal的呼叫。http://viridissoftware.wordpress.com/2014/07/29/paypal-ipn-payment-notification-example-in-c/

相关内容

最新更新