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

C# 我可以模拟一个私有方法吗?或者测试这个POST方法的正确方法是什么?,c#,asp.net-mvc,unit-testing,mocking,moq,C#,Asp.net Mvc,Unit Testing,Mocking,Moq,我有一个现有的ASP.NET MVC应用程序,想要创建一些单元测试,我很快遇到了下面的问题。是否有某种方式可以使用MOQ并说‘当运行私有方法GETCLIENTIP时,返回‘xxx’) 因为现在它使用的是HttpContext的一部分,当然单元测试没有 public HttpResponseMessage Post([FromBody]TriageCase TriageCase) { if (ModelState.IsValid) { //Get the IP ad

我有一个现有的ASP.NET MVC应用程序,想要创建一些单元测试,我很快遇到了下面的问题。是否有某种方式可以使用MOQ并说‘当运行私有方法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());
}

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


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

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

  • 可以使
    HttpContext
    GetClientIP
    方法不可知。然后把它做成内部的。用
    InternalsVisibleTo
    标记控制器组件,并放置单元测试组件路径
使方法不可知于
HttpContext
可以避免使用
HttpContextBase
(3.5以后的抽象http上下文类,用于启用测试)并提供模拟等(顺便说一句,您应该考虑一下。特别是对于MVC),将特定字符串作为参数传递给方法。e、 g.特定的服务器变量字符串

  • 您可以使
    GetClientIP
    方法接收HttpContextBase作为参数,然后将其设置为内部。用
    InternalsVisibleTo
    标记控制器组件,并放置单元测试组件路径
在控制器操作中,需要将此方法调用为
this.GetClientIP(新的HttpContextWrapper(HttpContext.Current))

单元测试可以设置可模拟的上下文。此外,您还可以在上下文中设置是否调用了请求属性,或者是否进行了与ip地址相关的服务器变量调用。(更不用说直接的ip地址值验证了)

  • 您可以使用FakeiTesy或Microsoft Moles等为私有方法创建私有访问器。我通常不会这样做

  • 您可以编写一个接口base
    INetworkUtility
    ,它有一个方法为您提供IP地址。您的控制器可以使用此接口。它也可以单独测试

  • 您可以使用一个公共助手类来获取ip地址,该地址可以进行单元测试

正如您所看到的,每个解决方案都需要进行一些权衡

无论mvc、web api或asp web表单如何,从请求对象获取IP地址都是一个独立的逻辑。(尽管仍然是特定于web的)因此将其作为助手方法或基于接口的助手方法并不有害


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

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

要么做依赖注入的事情,要么考虑一个“testdouble”或“accessor”类

对于双重测试-使
私有
方法a
受保护
,然后继承控制器并根据需要手动模拟输入或输出。我不是说这比国际奥委会好还是坏,我是说这是另一种方式

protected virtual string ExecuteIpnResponse(string url)
{
  var ipnClient = new WebClient();
  var ipnResponse = ipnClient.DownloadString(url);
  return ipnResponse;
}
我最近写了一篇关于这种测试风格的帖子,用于检查paypal呼叫。

你看过Fakeetisy吗?它应该能回答你的一些问题。尽管如此,ASP.NETMVC的调试难度是出了名的。考虑使用DI/IOC容器(如简单的注入器)注入某些逻辑块,这将使测试变得更容易。应用程序确实使用IOC作为控制器构造器库。但我想模仿的方法与此无关。。它只是一个使用了一些HttpContextI的私有方法,我看到添加它有帮助,但不确定为什么controller.Request=newHttpRequestMessage();