2012-10-11 176 views
3

我測試的MVC 3控制器調用這個類中的方法:嘲諷HttpContext.Current使用上NUnit測試MOQ

public class SessionVar 
{ 
    /// <summary> 
    /// Gets the session. 
    /// </summary> 
    private static HttpSessionState Session 
    { 
     get 
     { 
      if (HttpContext.Current == null) 
       throw new ApplicationException 
            ("No Http Context, No Session to Get!"); 

      return HttpContext.Current.Session; 
     } 
    } 

    public static T Get<T>(string key) 
    { 
     return Session[key] == null ? default(T) : (T)Session[key]; 
    } 
    ... 
} 

我的測試方法,以下從Hanselman's Blog的建議是:

[Test] 
public void CanRenderEmployeeList() 
{ 
    _mockIEmployeeService.Setup(s => s.GetEmployees(StatusFilter.OnlyActive)) 
     .Returns(BuildsEmployeeList().Where(e => e.IsApproved)); 

    var httpContext = FakeHttpContext(); 
    var target = _employeeController; 
    target.ControllerContext = new ControllerContext 
        (new RequestContext(httpContext, new RouteData()), target); 
    var result = target.Index(); 

    Assert.IsNotNull(result); 
    Assert.IsInstanceOf<ViewResult>(result); 
    var viewModel = target.ViewData.Model; 
    Assert.IsInstanceOf<EmployeeListViewModel>(viewModel); 
} 

public static HttpContextBase FakeHttpContext() 
{ 
    var context = new Mock<HttpContextBase>(); 
    var request = new Mock<HttpRequestBase>(); 
    var response = new Mock<HttpResponseBase>(); 
    var session = new Mock<HttpSessionStateBase>(); 
    var server = new Mock<HttpServerUtilityBase>(); 

    context.Setup(ctx => ctx.Request).Returns(request.Object); 
    context.Setup(ctx => ctx.Response).Returns(response.Object); 
    context.Setup(ctx => ctx.Session).Returns(session.Object); 
    context.Setup(ctx => ctx.Server).Returns(server.Object); 

    return context.Object; 
} 

但我的測試一直失敗,我得到:

CanRenderEmployeeListSystem.ApplicationException : No Http Context, 
                  No Session to Get! 

這是異常消息被thr自己當HttpContext.Current == null

我只需要Session對象'存在',而不是存儲在會話上的實際值。

你能告訴我什麼我做錯了嗎?

謝謝。

回答

2

從長遠來看,如果你創建了SessionVar類的接口,你會更快樂。在運行時使用您當前的實現(通過依賴注入)。在測試過程中插入模擬。消除了嘲笑所有這些Http運行時依賴關係的需要。

+0

這是我最後做的,不知何故,感覺就像一個解決辦法......但後來我發現其他人做同樣的方式和您的評論這裏經過:解決方法感覺幾乎消失:) – qbantek

2

Session屬性中的HttpContext.Current不受正在創建的模擬HttpContextBase的影響。也就是說,簡單地創建一個本地HttpContextBase不會自動填充HttpContext.Current。實際上HttpContext和HttpContextBase實際上沒有關係。你必須使用HttpContextWrapper來統一它們。

所以你最好將HttpContextWrapper實現傳遞給你的類SessionVar。在下面的代碼中,我已經將您的方法和屬性更改爲實例級別,以便我們可以在構造函數中設置上下文。如果沒有上下文傳遞給我們假定HttpContext.Current構造函數,但你也可以通過你的嘲笑比如在你的測試。

public class SessionVar 
{ 
    HttpContextWrapper m_httpContext; 

    public SessionVar(HttpContextWrapper httpContext = null) 
    { 
     m_httpContext = httpContext ?? new HttpContextWrapper(HttpContext.Current); 
    } 

    /// <summary> 
    /// Gets the session. 
    /// </summary> 
    private HttpSessionState Session 
    { 
     get 
     { 
      if (m_httpContext == null) 
       throw new ApplicationException("No Http Context, No Session to Get!"); 

      return m_httpContext.Session; 
     } 
    } 

    public T Get<T>(string key) 
    { 
     return Session[key] == null ? default(T) : (T)Session[key]; 
    } 
    ... 
} 
+0

我想這也是一個很好的解決方案,但我更喜歡@PatrickSteele的,事實上那是我結束實施的那個。感謝您的幫助。 – qbantek