在.NET Core中,按照Microsoft文档here中的模式,我们有一个控制器动作,该动作调用具有依赖项注入的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始终为null,因为似乎没有办法将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
}
答案 0 :(得分:0)
仅供参考:我认为微软的例子是错误的。一旦将View Component更改为View并将数据从View Component代码中获取到的数据移入控制器后,一切都变得易于测试和实现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");
}
错误请求单元测试如下所示(请注意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");
}