1

我有一个需要测试的控制器。它有一个方法,里面有函数。

public ActionResult GetZZ()
    {            
        ApplyResponseHeaders();
        var result = new MediaJsonResult();
        using (var str = new StreamReader(Request.InputStream))
            {
                string inputData = str.ReadToEnd();
                MyFunction(inputData, result);
            }
        return Json(result);
    }

我只想测试函数 MyFunction。这个函数是私有的。我怎样才能做到这一点。测试整个方法是没有必要的,因为在Request.InputStream中指定它的值的问题

4

3 回答 3

1

永远不要尝试测试私有方法。这些方法不是公共 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));
于 2013-08-19T16:30:49.650 回答
0

一种简单的方法是将方法公开。如果您不能(或不想),您可以使方法受保护而不是私有,然后在您的测试程序集中子类化您的控制器并通过派生类型对其进行测试。

像这样:

public class TesterController : YourController
{
    public new ActionResult MyFunction(string inputData, MediaJsonResult result)
    {
        return base.MyFunction(inputData, result);
    }
}
于 2013-08-19T15:14:24.540 回答
0

您可以将方法标记为内部而不是私有,然后在控制器的 AssemblyInfo.cs 中添加 InternalsVisibleTo("Path.To.Test.Project")。

不是 100% 肯定同意永远不要在你的代码中测试私有方法。像大多数事情一样,有时它是有道理的,务实往往比教条更好。

于 2014-02-03T20:09:31.720 回答