【问题标题】:Nancy testing GetModel<T> throws KeyNotFoundException南希测试 GetModel<T> 抛出 KeyNotFoundException
【发布时间】:2014-09-04 17:32:07
【问题描述】:

我正在尝试测试从我的 Nancy 应用程序返回的模型是否符合预期。我遵循了文档here,但每当我调用GetModel&lt;T&gt; 扩展方法时,它都会抛出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);
    }
}

调试这个测试表明该模块被命中并且完成得很好。运行应用程序显示响应符合预期。

有人能解释一下吗?

【问题讨论】:

  • 我相信GetModel&lt;T&gt; 的目的是让模型位于渲染的 html 视图后面。您可以将 json 反序列化到 SanityModel 进行检查。

标签: nancy


【解决方案1】:

感谢可爱的家伙albertjanthe.fringe.ninja,在Nancy Jabbr room 中,我们已经对这里发生的事情进行了解释。

TL;DR 这不起作用是有道理的,但错误消息应该更具描述性。下面有一个解决方法。

这里的问题是我在使用TestingViewFactory 时请求以application/json 的响应。

我们来看看GetModel&lt;T&gt;();的实现

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

这只是从NancyContext 中获取视图模型并将其转换为您的类型。 这是引发错误的地方,因为NancyContext 中没有视图模型。这是因为视图模型是在TestingViewFactoryRenderView 方法中添加到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&lt;T&gt;

解决方法

我的应用程序是一个 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&lt;T&gt; 应该可以在不需要视图的情况下工作。

【讨论】:

  • 哎呀我的头......我最终只是自己反序列化响应,而不是试图让GetModel&lt;&gt;工作。
  • 很好的解释——至少我知道我没有疯。不幸的是,这对我不起作用。我正在使用 MSTest,所以没有为我定义 Fixtures.SystemUnderTest.ViewModelKey
猜你喜欢
  • 1970-01-01
  • 2013-05-14
  • 2013-02-21
  • 1970-01-01
  • 2011-11-13
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多