我想在我的控制器中测试一个动作,该动作使用controllerContext作为参数来生成基于第3部分库" Rotativa"的pdf文档。
这是动作(函数)的实现:
public ActionResult DetailsPrint(int? id)
{
var a = new ViewAsPdf();
a.ViewName = "../Ops/_2A1/Details";
a.Model =UnitOfWork._2A1s.Get(id.Value);
var pdfBytes = a.BuildPdf(ControllerContext);
// return ActionResult
MemoryStream ms = new MemoryStream(pdfBytes);
return new FileStreamResult(ms, "application/pdf");
}
以下是我尝试进行单元测试的方法:
构造
public _2A1ControllerTest()
{
_mockRepository = new Mock<I2A1Repository>();
var mockUoW = new Mock<IUnitOfWork>();
_mockHttpContext = new Mock<HttpContextBase>();
_mockRequest = new Mock<HttpRequestBase>();
_mockDisplayModeContext = new Mock<IDisplayMode>();
mockUoW.SetupGet(u => u._2A1s).Returns(_mockRepository.Object);
_mockHttpContext.SetupGet(x => x.Request).Returns(_mockRequest.Object);
_controller = new _2A1Controller(mockUoW.Object);
_controller.MockCurrentUser("test.admin");
_controller.ControllerContext = new ControllerContext(_mockHttpContext.Object, new System.Web.Routing.RouteData(), _controller);
}
测试功能
[TestMethod]
public void DetailsPrint_shouldPrint()
{
var result = _controller.DetailsPrint(1) as ActionResult;
result.Should().BeOfType<ActionResult>();
}
测试名称:DetailsPrint_shouldPrint 测试FullName:OPSReviewTest._2A1ControllerTest.DetailsPrint_shouldPrint 测试源:C:\ inetpub \ wwwroot \ OpsReview \ OPSReviewTest \ Controllers \ Api_2A1ControllerTest.cs:第46行 测试结果:失败 测试持续时间:0:04:39,3039007 结果StackTrace:
在System.Web.WebPages.DisplayModeProvider.GetDisplayMode(HttpContextBase context) 在System.Web.Mvc.ControllerContext.get_DisplayMode() 结果消息: 测试方法OPSReviewTest._2A1ControllerTest.DetailsPrint_shouldPrint抛出异常: System.NullReferenceException:未将对象引用设置为对象的实例。
任何帮助或建议,谢谢。
答案 0 :(得分:1)
您是否正在尝试对您不拥有的代码进行单元测试? (羞耻,[贝尔收费],羞耻......)
如果目标是单独测试控制器操作流程,则建议抽象出第三方PDF生成,以便可以模拟它以便于测试。
public interface IViewAsPdfWrapper {
string ViewName { get; set; }
object Model { get; set; }
byte[] BuildPdf(ControllerContext context);
}
public class ViewAsPdfWrapper : IViewAsPdfWrapper {
private readonly ViewAsPdf view;
public ViewAsPdfWrapper() {
view = new ViewAsPdf();
}
public string ViewName { get; set; }
public object Model { get; set; }
public byte[] BuildPdf(ControllerContext context) {
view.ViewName = ViewName;
view.Model = Model;
return view.BuildPdf(context);
}
}
现在可以根据需要将抽象注入到控制器中,以便根据请求操作使用。
public class _2A1Controller : Controller {
private readonly IUnitOfWork UnitOfWork;
private readonly IViewAsPdfWrapper viewAsPdf;
public _2A1Controller(IUnitOfWork uow, IViewAsPdfWrapper viewAsPdf) {
this.UnitOfWork = uow;
this.viewAsPdf = viewAsPdf;
}
public ActionResult DetailsPrint(int? id) {
var a = viewAsPdf;
a.ViewName = "../Ops/_2A1/Details";
a.Model = UnitOfWork._2A1s.Get(id.Value);
var pdfBytes = a.BuildPdf(ControllerContext);
// return ActionResult
MemoryStream ms = new MemoryStream(pdfBytes);
return new FileStreamResult(ms, "application/pdf");
}
}
现在单元测试可以安全地模拟第三方功能
public _2A1ControllerTest() {
_mockRepository = new Mock<I2A1Repository>();
var mockUoW = new Mock<IUnitOfWork>();
mockUoW.SetupGet(u => u._2A1s).Returns(_mockRepository.Object);
var mockViewAsPdf = new Mock<IViewAsPdfWrapper>();
mockViewAsPdf.Setup(m => m.BuildPdf(It.IsAny<ControllerContext>()))
.Returns(() => new byte[0]);
_mockRequest = new Mock<HttpRequestBase>();
_mockHttpContext = new Mock<HttpContextBase>();
_mockHttpContext.SetupGet(x => x.Request).Returns(_mockRequest.Object);
_controller = new _2A1Controller(mockUoW.Object, mockViewAsPdf.Object);
_controller.MockCurrentUser("test.admin");
_controller.ControllerContext = new ControllerContext(_mockHttpContext.Object, new System.Web.Routing.RouteData(), _controller);
}
假设使用FluentAssertions,测试方法应如下所示(Pun意图:))
[TestMethod]
public void DetailsPrint_shouldPrint() {
var result = _controller.DetailsPrint(1) as ActionResult;
result.Should()
.NotBeNull()
.And
.BeAssignableTo<ActionResult>();
}
最后,不要忘记在生产中注册DI容器的界面及其实现。
答案 1 :(得分:0)
您忘记将DsiplayMode
属性分配给ControllerContext
添加此内容:
_controller.ControllerContext.DisplayMode=_mockDisplayModeContext.Object;