【问题标题】:Testing .NET Core Controller View Component测试 .NET Core 控制器视图组件
【发布时间】:2018-06-22 20:56:16
【问题描述】:

在 .NET Core 中,我们有一个控制器操作调用具有依赖注入的 ViewComponent,遵循 Microsoft 文档 here 中的模式。

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

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 注入到 Controller 中,然后再注入到 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
}

【问题讨论】:

    标签: c# asp.net-core asp.net-core-2.0


    【解决方案1】:

    仅供参考:我认为微软的例子是错误的。一旦我将 View Component 更改为 View 并将数据从 View Component 代码中提取并移到 Controller 中,那么一切都变得容易测试和实现 Bad Request 逻辑,等等。只需记住将 View Component 移出 View Component 目录并在视图中将 layout 设置为 null 即可。

    控制器应该看起来更像这样:

    public class MyController : Controller
    {
        private readonly IToDoContext _db;
        public MyController(IToDoContext db)
        {
            _db = db;
        }
    
        public async Task<IActionResult> IndexVC("PriorityList", new { maxPriority, isDone = false })
            {
                if (string.IsNullOrWhiteSpace(maxPriority))
                    return BadRequest($"maxPriority cannot be empty");
    
                var model = await InvokeAsync(maxPriority, isDone);
    
                if (model == null)
                {
                    return BadRequest($"model not found");
                }
    
                return View(model);
            }
    
        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();
            }
    }
    

    单元测试如下所示:

    [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 = await sut.PriorityList("myparams") as ViewResult;
        result.Model.ShouldNotBeNull();
        var resultModel = result.Model as PriorityListModel;
        resultModel.ShouldNotBeNull();
        resultModel.Thing.ShouldBe("whatever");
    }
    

    Bad Request 单元测试看起来像这样(注意 BadRequestObjectResult):

    [Fact]
    public async Task Should_return_bad_request_if_result_not_found()
    {
        var mockToDoContext = new Mock<IToDoContext>();
        mockToDoContext.Setup(m => m.Get())
            .ReturnsAsync(null);
    
        var httpContext = new DefaultHttpContext();
    
        var sut = new MyController(mockToDoContext.Object)
        {
            ControllerContext = new ControllerContext { HttpContext = httpContext }
        };
        var result = await sut.PriorityList("myparams") as BadRequestObjectResult;
    
        result.ShouldNotBeNull();
        result.StatusCode.ShouldBe(400);
        result.Value.ShouldBe("model not found");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-28
      • 1970-01-01
      • 1970-01-01
      • 2017-12-12
      • 2021-01-10
      • 1970-01-01
      相关资源
      最近更新 更多