不要試圖不斷測試私有方法。這些方法不是公共API的一部分,不能由調用者調用。您的目標是滿足公共API的要求。私人方法是否按預期工作並不重要。從調用者的角度來看,這種方法不存在,也沒有任何價值。
相反,你應該測試功能,這可以通過公共API,GetZZ()
方法在你的情況。但是你應該嘲笑外部依賴,以便用你想要的任何測試數據來隔離測試你的控制器。
所以,在這裏你有兩個選擇。第一個是嘲笑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));
通常我們不需要測試私有方法,您是否有任何特定的理由這樣做? – Anuraj
原因是我無法在Request.InputStream中輸入值,因此決定這麼做並僅測試此方法 –
MyFunction()是做什麼的?它是否應該封裝在自己的類型中,並由控制器調用,還是與控制器相關的東西,並取決於控制器中的某些字段? –