永远不要尝试测试私有方法。这些方法不是公共 API 的一部分,不能被调用者调用。您的目标是满足公共 API 的要求。私有方法是否按预期工作并不重要。从调用者的角度来看,这个方法不存在,也没有任何价值。
相反,您应该测试功能,这可以通过公共 APIGetZZ()
方法在您的情况下使用。但是您应该模拟外部依赖项,以便使用您想要的任何测试数据单独测试您的控制器。
所以,在这里你有两个选择。第一个是模拟HttpRequest
你的控制器所依赖的,并为输入流提供测试数据(你必须做很多工作):
var httpRequest = new Mock<HttpRequestBase>();
var stream = new MemoryStream(Encoding.Default.GetBytes("Hello world"));
httpRequest.Setup(r => r.InputStream).Returns(stream);
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(c => c.Request).Returns(httpRequest.Object);
var controller = new HomeController();
var routeData = new RouteData();
controller.ControllerContext = // set mocked context
new ControllerContext(httpContext.Object, routeData, controller);
var result = (JsonResult)controller.GetZZ();
Assert.That(result.Data, Is.EqualTo(42)); // your assertions here
另一种选择 - 将这个与环境相关的东西隐藏在一些抽象下,可以很容易地模拟(当然,你应该使用更好的名字):
public interface IFoo
{
string Bar();
}
这是一个实现,它使用当前上下文请求来获取输入数据:
public class Foo : IFoo
{
public string Bar()
{
using (var str = new StreamReader(HttpContext.Current.Request.InputStream))
{
string inputData = str.ReadToEnd();
return inputData;
}
}
}
使控制器依赖于这个抽象:
public class HomeController : Controller
{
private readonly IFoo _foo;
public HomeController(IFoo foo) // inject dependency
{
_foo = foo;
}
public ActionResult GetZZ()
{
ApplyResponseHeaders();
var result = new JsonResult();
MyFunction(_foo.Bar(), result); // use dependency
return result;
}
}
现在您可以毫无问题地模拟它:
var foo = new Mock<IFoo>();
foo.Setup(f => f.Bar()).Returns("Hello, TDD");
var controller = new HomeController(foo.Object);
var result = (JsonResult)controller.GetZZ();
Assert.That(result.Data, Is.EqualTo(42));