Насмешка над контроллером для проверки ViewEngine внутри Area - nullreference и RouteData
У меня есть Area
на моем сайте MVC. Эта область имеет типичную настройку Контроллер / Модель / Вид.
В качестве контроллера у меня есть следующий код:
public class DocumentCreatorController : Controller
{
// GET: Templates/DocumentCreator
public ActionResult OfferTemplate(BaseDocumentViewModel data)
{
return this.Pdf(nameof(OfferTemplate), data, "File.pdf");
}
}
Метод this.Pdf
делает пару вещей, но интересно то, что все сводится к вызову ViewEngine:
var viewResult = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName);
Здесь я называю FindPartialView
с ControllerContext
и PartialViewName
, мой PartialViewName
исходит от nameof(OfferTemplate)
от действия контроллера OfferTemplate
, я думаю controllercontext
это моя задача
Моя задача:
Когда я хочу настроить это в модульном тесте (используя Moq), у меня есть следующий код, основанный на таких страницах, как Mocking Класс RouteData в System.Web.Routing для приложений MVC и контекст контроллера Mocking Asp.net-mvc:
[TestMethod]
public void OfferTemplate()
{
var ctr = SetupControllerWithContext();
}
private static DocumentCreatorController SetupControllerWithContext()
{
var routeData = new RouteData();
routeData.Values.Add("controller", "DocumentCreatorController");
routeData.Values.Add("action", "OfferTemplate");
var request = new Mock<HttpRequestBase>();
request.Expect(r => r.HttpMethod).Returns("GET");
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object
, routeData, new Mock<ControllerBase>().Object);
DocumentCreatorController ctr = new DocumentCreatorController();
ctr.ControllerContext = controllerContext;
return ctr;
}
Что дает следующую ошибку:
Eesy.Websites.Api.Tests.Controllers.DocumentCreatorControllerTest.OfferTemplate сгенерировал исключение: System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта.
Это я не понимаю.
Настройка моей папки:
Отладка изображения в Controller Context при вызове FindPartialView:
У кого-нибудь есть идея? Это потому, что я неправильно настроил RouteData?
1 ответ
Вы пытаетесь смоделировать и протестировать код фреймворка. Абстрагируйте эту функциональность в код, которым вы управляете, чтобы вы могли тестировать отдельно, если это необходимо.
В настоящее время действие и, следовательно, контроллер тесно связаны с внешними сторонними зависимостями. Если цель состояла в том, чтобы протестировать поток действий контроллера изолированно, то рекомендуется абстрагировать стороннее поколение PDF, чтобы его можно было смоделировать для облегчения тестирования.
public interface IDocumentService {
ActionResult ToPdf(Controller arg1, string arg2, object arg3, string arg4);
}
Контроллер будет явно зависеть от этой абстракции через внедрение конструктора.
public class DocumentCreatorController : Controller {
private readonly IDocumentService render;
DocumentCreatorController(IDocumentService render) {
this.render = render;
}
// GET: Templates/DocumentCreator
public ActionResult OfferTemplate(BaseDocumentViewModel data) {
return render.ToPdf(this, nameof(OfferTemplate), data, "File.pdf");
}
}
Итак, теперь, чтобы протестировать процесс генерации pdf контроллера, вам нужно только смоделировать абстракцию.
[TestMethod]
public void OfferTemplate() {
//Arrange
var serviceMock = new Mock<IDocumentService>();
//...setup mock for use case
var controller = new DocumentCreatorController(serviceMock.Object);
var data = new BaseDocumentViewModel {
//...
};
//Act
var actual = controller.OfferTemplate(data);
//Assert
//...assert behavior
}
Фактическая реализация службы будет инкапсулировать фактическую функциональность и будет зарегистрирована в контейнере внедрения зависимостей вместе с абстракцией.
Чтобы проверить фактическое поколение, вам нужно сделать интеграционный тест, который является другой темой.