2014-09-03 23 views
3

我想測試從我的南希應用程序返回的模型是否如預期。我按照文檔here,但每當我打電話給GetModel<T>擴展方法它會拋出一個KeyNotFoundException南希測試GetModel <T>拋出KeyNotFoundException

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary. 

我知道錯誤的含義,但我不明白爲什麼它被拋出。

這裏是我的模塊

public class SanityModule : NancyModule 
{ 
    public SanityModule() 
    { 
     Get["sanity-check"] = _ => Negotiate.WithModel(new SanityViewModel { Id = 1 }) 
              .WithStatusCode(HttpStatusCode.OK); 
    } 
} 

我的視圖模型

public class SanityViewModel 
{ 
    public int Id { get; set; } 
} 

,這裏是我的測試

[TestFixture] 
public class SanityModuleTests 
{ 
    [Test] 
    public void Sanity_Check() 
    { 
     // Arrange 
     var browser = new Browser(with => 
     { 
      with.Module<SanityModule>(); 
      with.ViewFactory<TestingViewFactory>(); 
     }); 

     // Act 
     var result = browser.Get("/sanity-check", with => 
     { 
      with.HttpRequest(); 
      with.Header("accept", "application/json"); 
     }); 
     var model = result.GetModel<SanityViewModel>(); 

     // Asset 
     model.Id.ShouldBeEquivalentTo(1); 
    } 
} 

調試這個測試表明,該模塊被擊中並完成就好了。運行該應用程序顯示響應如預期。

任何人都可以對此有所瞭解嗎?

+0

我相信'GetModel '是爲了讓模型在渲染的html視圖背後。你可以將json反序列化到SanityModel來檢查它。 – albertjan 2014-09-03 20:16:06

回答

3

感謝可愛的傢伙,albertjanthe.fringe.ninja,在Nancy Jabbr room我們已經解釋了這裏發生了什麼。

TL; DR這是行不通的,但錯誤信息應該更具描述性。下面有一個解決方法。

這裏的問題是,我要求的響應爲application/json,同時使用TestingViewFactory

讓我們來看看GetModel<T>();

public static TType GetModel<TType>(this BrowserResponse response) 
{ 
    return (TType)response.Context.Items[TestingViewContextKeys.VIEWMODEL]; 
} 

這簡直是抓住從NancyContext視圖模型,並將其投射到您的類型實現。 這是錯誤發生的位置,因爲NancyContext中沒有視圖模型。這是因爲視圖模型被添加到RenderView方法TestingViewFactory的NancyContext中。

public Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext) 
{ 
    // Intercept and store interesting stuff 
    viewLocationContext.Context.Items[TestingViewContextKeys.VIEWMODEL] = model; 
    viewLocationContext.Context.Items[TestingViewContextKeys.VIEWNAME] = viewName; 
    viewLocationContext.Context.Items[TestingViewContextKeys.MODULENAME] = viewLocationContext.ModuleName; 
    viewLocationContext.Context.Items[TestingViewContextKeys.MODULEPATH] = viewLocationContext.ModulePath; 

    return this.decoratedViewFactory.RenderView(viewName, model, viewLocationContext); 
} 

我的測試是請求json所以RenderView將不會被調用。這意味着如果您使用html請求,則只能使用GetModel<T>

解決方法

我的應用程序是一個API,所以我沒有任何意見,使轉產

with.Header("accept", "application/json"); 

with.Header("accept", "text/html"); 

將拋出一個ViewNotFoundException。爲了避免這種情況,我需要實現我自己的IViewFactory。(這是來自the.fringe.ninja

public class TestViewFactory : IViewFactory 
{ 
    #region IViewFactory Members 

    public Nancy.Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext) 
    { 
     viewLocationContext.Context.Items[Fixtures.SystemUnderTest.ViewModelKey] = model; 
     return new HtmlResponse(); 
    } 

    #endregion 
} 

然後是簡單地更新

with.ViewFactory<TestingViewFactory>(); 

with.ViewFactory<TestViewFactory>(); 

的情況下,現在應該GetModel<T>無需一道努力。

+1

哎呀我的頭......我結束了反序列化自己的反應,而不是試圖讓'GetModel <>'工作。 – ESG 2016-06-20 19:29:26

+0

很好的解釋 - 至少我知道我並不瘋狂。不幸的是,這並不適合我。我正在使用MSTest,因此'Fixtures.SystemUnderTest.ViewModelKey'沒有爲我定義。 – JamesQMurphy 2016-12-17 23:04:33