我有一个现有的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());
}
答案 0 :(得分:3)
以适当的TDD方式,你不进行单元测试"私人"或"内部"方法。单元测试中仅使用公共接口。如果你对一个私有/内部方法进行单元测试,那么你就会将你的单元测试与特定的实现紧密联系起来。
应该做的是使用依赖注入来注入实现"依赖"的类/接口。您需要进行单元测试的功能。这将有助于进一步模块化您的代码,从而使维护更容易。
答案 1 :(得分:1)
有几种方法可以做到这一点,从讨厌的复杂问题到简单的交易问题。这里有一些:
GetClientIP
方法与HttpContext
无关。然后把它变成内部的。用InternalsVisibleTo
标记控制器组件并放置单元测试组件路径。使该方法与HttpContext
无关,使您免于拥有HttpContextBase
(从3.5开始的抽象http上下文类以启用测试)并提供模拟等等。(顺便说一下,你应该考虑一下特别是对于MVC而言,将特定字符串作为参数传递给方法。例如特定的服务器变量字符串。
GetClientIP
方法接收HttpContextBase作为参数,然后将其设为内部。用InternalsVisibleTo
标记控制器组件并放置单元测试组件路径。 在您的控制器操作中,您需要将此方法称为this.GetClientIP(new HttpContextWrapper(HttpContext.Current))
您的单元测试可以设置可模拟的上下文。还有更多,您可以在上下文中设置是否调用Request属性,或者是否进行了与ip地址相关的服务器变量调用。 (更不用说直接IP地址值验证)
您可以使用FakeItEasy或Microsoft Moles等为私有方法创建私有访问器。我通常不会这样做。
您可以编写一个接口库INetworkUtility
,它有一个方法可以为您提供IP地址。你的控制器可以使用这个界面。它也可以单独测试。
你可以有一个公共助手类来获取ip地址,可以进行单元测试。
正如您所看到的,每个解决方案都需要做一些权衡。
从Request对象获取IP地址是一个独立的逻辑,不管mvc或web api或asp web表单。 (尽管仍然是Web特定的)因此将它作为辅助方法或基于接口的辅助方法没有害处。
个人而言,我更喜欢内部方法,(因为它几乎是私有的)并且不需要太多的代码更改。答案 2 :(得分:0)
我一般不尝试测试私有方法。它只是变得混乱 - 测试动作的输入和输出......
要么执行依赖注入,要么考虑“测试双重”或“访问者”类......
对于 test double - 将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/