测试 .NET Core 控制器视图组件

在.NET的核心,我们有在呼唤具有依赖注入ViewComponent,按照微软的文档模式的控制器操作在这里。


如果我们有一个控制器动作返回这样的渲染视图:


public class MyController : Controller

{

    private readonly IToDoContext _todoContext;

    public MyController(IToDoContext todoContext)

    {

        _todoContext = todoContext;

    }


    public IActionResult IndexVC()

    {

        return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });

    }

}

还有一个具有如下依赖注入的 ViewComponent:


public class PriorityListViewComponent : ViewComponent

{

    private readonly ToDoContext db;


    public PriorityListViewComponent(ToDoContext context)

    {

        db = context;

    }


    public async Task<IViewComponentResult> InvokeAsync(int maxPriority, bool isDone)

    {

        var items = await GetItemsAsync(maxPriority, isDone);

        return View(items);

    }

    private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)

    {

        return db.ToDo.Where(x => x.IsDone == isDone && x.Priority <= maxPriority).ToListAsync();

    }

}

我们如何在控制器动作单元测试中将 ToDoContext 注入到 ViewComponent 中?到目前为止, result.Model 始终为空,因为似乎没有办法将 ToDoContext db 注入控制器,然后再注入 ViewComponent。


[Fact]

public void Should_return_viewcomponent()

{

    var mockToDoContext = new Mock<IToDoContext>();

    mockToDoContext.Setup(m => m.Get()).ReturnsAsync(new ToDoContext());


    var sut = new MyController(mockToDoContext.Object);


    var result = sut.PriorityListViewComponent("myparams") as ViewComponentResult;

    // ToDoContext db is never set, so the result.Model is always null

}


MMMHUHU
浏览 183回答 1
1回答

隔江千里

仅供参考:我认为微软的例子是错误的。一旦我将 View Component 更改为 View 并将数据从 View Component 代码中获取到后面并移到 Controller 中,那么一切都变得容易测试和实现 Bad Request 逻辑,等等。只需记住将 View Component 移出 View Component 目录,并在视图中将 layout 设置为 null。控制器应该看起来更像这样:public class MyController : Controller{&nbsp; &nbsp; private readonly IToDoContext _db;&nbsp; &nbsp; public MyController(IToDoContext db)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _db = db;&nbsp; &nbsp; }&nbsp; &nbsp; public async Task<IActionResult> IndexVC("PriorityList", new { maxPriority, isDone = false })&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (string.IsNullOrWhiteSpace(maxPriority))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return BadRequest($"maxPriority cannot be empty");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var model = await InvokeAsync(maxPriority, isDone);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (model == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return BadRequest($"model not found");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return View(model);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; public async Task<IViewComponentResult> InvokeAsync(&nbsp; &nbsp; &nbsp; &nbsp; int maxPriority, bool isDone)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var items = await GetItemsAsync(maxPriority, isDone);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return View(items);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return _db.ToDo.Where(x => x.IsDone == isDone &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x.Priority <= maxPriority).ToListAsync();&nbsp; &nbsp; &nbsp; &nbsp; }}单元测试看起来像:[Fact]public void Should_return_viewcomponent(){&nbsp; &nbsp; var mockToDoContext = new Mock<IToDoContext>();&nbsp; &nbsp; mockToDoContext.Setup(m => m.Get())&nbsp; &nbsp; &nbsp; &nbsp; .ReturnsAsync(new ToDoContext());&nbsp; &nbsp; var sut = new MyController(mockToDoContext.Object);&nbsp; &nbsp; var result = await sut.PriorityList("myparams") as ViewResult;&nbsp; &nbsp; result.Model.ShouldNotBeNull();&nbsp; &nbsp; var resultModel = result.Model as PriorityListModel;&nbsp; &nbsp; resultModel.ShouldNotBeNull();&nbsp; &nbsp; resultModel.Thing.ShouldBe("whatever");}Bad Request 单元测试看起来像这样(注意 BadRequestObjectResult):[Fact]public async Task Should_return_bad_request_if_result_not_found(){&nbsp; &nbsp; var mockToDoContext = new Mock<IToDoContext>();&nbsp; &nbsp; mockToDoContext.Setup(m => m.Get())&nbsp; &nbsp; &nbsp; &nbsp; .ReturnsAsync(null);&nbsp; &nbsp; var httpContext = new DefaultHttpContext();&nbsp; &nbsp; var sut = new MyController(mockToDoContext.Object)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; ControllerContext = new ControllerContext { HttpContext = httpContext }&nbsp; &nbsp; };&nbsp; &nbsp; var result = await sut.PriorityList("myparams") as BadRequestObjectResult;&nbsp; &nbsp; result.ShouldNotBeNull();&nbsp; &nbsp; result.StatusCode.ShouldBe(400);&nbsp; &nbsp; result.Value.ShouldBe("model not found");}
打开App,查看更多内容
随时随地看视频慕课网APP