Насмешка над контроллером для проверки 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
}

Фактическая реализация службы будет инкапсулировать фактическую функциональность и будет зарегистрирована в контейнере внедрения зависимостей вместе с абстракцией.

Чтобы проверить фактическое поколение, вам нужно сделать интеграционный тест, который является другой темой.

Другие вопросы по тегам