2013-08-19 52 views
1

我有一個需要測試的控制器。它有一個函數裏面的方法。單元測試方法ASP。 NET(NUnit)

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中指定其值的問題

+0

通常我們不需要測試私有方法,您是否有任何特定的理由這樣做? – Anuraj

+0

原因是我無法在Request.InputStream中輸入值,因此決定這麼做並僅測試此方法 –

+0

MyFunction()是做什麼的?它是否應該封裝在自己的類型中,並由控制器調用,還是與控制器相關的東西,並取決於控制器中的某些字段? –

回答

1

不要試圖不斷測試私有方法。這些方法不是公共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)); 
0

一個簡單的方法是使該方法公開。如果你不能(或不想),你可以使該方法受保護而不是私有,然後在你的測試程序集中對控制器進行子類化並通過派生類型對其進行測試。

事情是這樣:

public class TesterController : YourController 
{ 
    public new ActionResult MyFunction(string inputData, MediaJsonResult result) 
    { 
     return base.MyFunction(inputData, result); 
    } 
} 
0

可以標記方法是內部的,而不是私人,然後添加一個InternalsVisibleTo(「路徑.To.Test.Project「)在控制器的AssemblyInfo.cs中。

不是100%確定同意永遠不要在您的代碼中測試私有方法。像大多數事情一樣,有時候這是有道理的,而務實的做法往往比教條式的更好。