2014-09-03 1 views
3

Я пытаюсь проверить, что модель, возвращенная из моего приложения Nancy, как и ожидалось. Я следил за документами here, но всякий раз, когда я вызываю метод расширения GetModel<T>, он выдает KeyNotFoundException.Нэнси тестирование GetModel <T> throws 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-представлением. Вы можете просто deserialise json для SanityModel, чтобы проверить это. – albertjan

ответ

3

Благодаря прекрасным ребятам, albertjan и the.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. Это связано с тем, что модель представления добавлена ​​в NancyContext в методе RenderViewTestingViewFactory.

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 не будет вызываться. Это означает, что вы можете использовать только GetModel<T>, если вы используете запрос html.

Обход

Мое приложение является апи поэтому у меня нет никакого мнения так перепрофилирования

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

Ouch my head ... Я закончил просто Deserializing ответ сам, вместо того, чтобы пытаться заставить GetModel <> 'работать. – ESG

+0

Хорошее объяснение - по крайней мере, я знаю, что я не сумасшедший. К сожалению, это не сработало для меня. Я использую MSTest, поэтому «Fixtures.SystemUnderTest.ViewModelKey» не был определен для меня. – JamesQMurphy

Смежные вопросы