Nancy测试GetModel <t>抛出KeyNotFoundException </t>

时间:2014-09-03 19:54:21

标签: nancy

我试图测试从我的Nancy应用程序返回的模型是否符合预期。我已按照文档here进行了操作,但每当我调用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);
    }
}

调试此测试表明模块已命中并完成正常。运行应用程序会显示响应符合预期。

任何人都可以对此有所了解吗?

1 个答案:

答案 0 :(得分: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的{​​{1}}方法添加到NancyContext。

TestingViewFactory

我的测试是请求json,因此不会调用RenderView。这意味着如果您使用html请求,则只能使用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); }

解决方法

我的申请是api,所以我没有任何意见,所以改变行

GetModel<T>

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

将抛出with.Header("accept", "text/html"); 。为避免这种情况,我需要实现自己的ViewNotFoundException。 (这来自the.fringe.ninja

IViewFactory

然后只是一个更新的案例

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>(); 可以在不需要视图的情况下工作。