我的MVC网站中有一个Area
。该区域具有典型的控制器/模型/视图设置。
作为控制器,我有以下代码:
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 The RouteData Class in System.Web.Routing for MVC applications和Mocking Asp.net-mvc Controller Context等页面提供以下代码:
[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:未将对象引用设置为对象的实例。
这个我不明白。
我的文件夹设置:
调用FindPartialView时调试ControllerContext上的图像:
有人有想法吗? 是因为我设置了RouteData错了吗?
答案 0 :(得分: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
}
该服务的实际实现将封装实际功能,并将与依赖注入容器一起注册以及抽象。
要测试实际生成,您需要进行集成测试,这是另一个主题。