如何单元测试Core MVC控制器动作是否调用ControllerBase.Problem() [英] How to unit test whether a Core MVC controller action calls ControllerBase.Problem()
问题描述
我们有一个从ControllerBase
派生的控制器,其动作如下:
We have a controller that derives from ControllerBase
with an action like this:
public async Task<ActionResult> Get(int id)
{
try
{
// Logic
return Ok(someReturnValue);
}
catch
{
return Problem();
}
}
我们也有这样的单元测试:
We also have a unit test like this:
[TestMethod]
public async Task GetCallsProblemOnInvalidId()
{
var result = sut.Get(someInvalidId);
}
但是ControllerBase.Problem()
会引发Null引用异常.这是Core MVC框架中的一种方法,因此我真的不知道为什么它会引发错误.我认为可能是因为HttpContext为null,但是我不确定.
是否存在标准化方法来测试控制器应调用Problem()
的测试用例?
任何帮助表示赞赏.
如果答案涉及嘲笑:我们使用Moq和AutoFixtrue.
But ControllerBase.Problem()
throws a Null Reference Exception. This is a method from the Core MVC framework, so I don't realy know why it is throwing the error. I think it may be because HttpContext is null, but I'm not sure.
Is there a standardized way to test a test case where the controller should call Problem()
?
Any help is appreciated.
If the answer involves mocking: we use Moq and AutoFixtrue.
推荐答案
空异常是由于缺少ProblemDetailsFactory
在这种情况下,控制器需要能够通过以下方式创建ProblemDetails
实例:
In this case the controller needs to be able to create ProblemDetails
instance via
[NonAction]
public virtual ObjectResult Problem(
string detail = null,
string instance = null,
int? statusCode = null,
string title = null,
string type = null)
{
var problemDetails = ProblemDetailsFactory.CreateProblemDetails(
HttpContext,
statusCode: statusCode ?? 500,
title: title,
type: type,
detail: detail,
instance: instance);
return new ObjectResult(problemDetails)
{
StatusCode = problemDetails.Status
};
}
ProblemDetailsFactory
是可设置的属性
public ProblemDetailsFactory ProblemDetailsFactory
{
get
{
if (_problemDetailsFactory == null)
{
_problemDetailsFactory = HttpContext?.RequestServices?.GetRequiredService<ProblemDetailsFactory>();
}
return _problemDetailsFactory;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_problemDetailsFactory = value;
}
}
在单独测试时可能会被模拟和填充.
that could be mocked and populated when testing in isolation.
[TestMethod]
public async Task GetCallsProblemOnInvalidId() {
//Arrange
var problemDetails = new ProblemDetails() {
//...populate as needed
};
var mock = new Mock<ProblemDetailsFactory>();
mock
.Setup(_ => _.CreateProblemDetails(
It.IsAny<HttpContext>(),
It.IsAny<int?>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>())
)
.Returns(problemDetails)
.Verifyable();
var sut = new MyController(...);
sut.ProblemDetailsFactory = mock.Object;
//...
//Act
var result = await sut.Get(someInvalidId);
//Assert
mock.Verify();//verify setup(s) invoked as expected
//...other assertions
}
这篇关于如何单元测试Core MVC控制器动作是否调用ControllerBase.Problem()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!