如何使用返回类型ActionResult< T>对动作进行单元测试? [英] How to unit-test action with return type ActionResult<T>?
问题描述
我的问题与这个问题非常相似:
My question is very similar to this one:
问题是我的问题混入了通用 ActionResult< T>
类型, async
和 Ok(..)
.我似乎无法使链接问题的答案适应一般情况.也许我的情况略有不同.
The problem is that my question mixes in the generic ActionResult<T>
type, async
, and Ok(...)
. I can't seem to adapt linked question's answer to the generic situation. Or possibly my scenario is subtly different.
这是一个复制品.创建新的"API"类型的ASP.NET Core Web应用程序.将一个新的xUnit .NET Core测试项目添加到该解决方案中,该项目引用该API项目(以及任何所需的框架库).分别创建控制器和测试,如下所示:
Here's a repro. Create new ASP.NET Core Web Application of "API" type. Add a new xUnit .NET Core test project to the solution, that references the API project (as well as any needed framework libs). Create the controller and tests like this, respectively:
public class Thing { public string Name => "Foobar"; }
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public async Task<ActionResult<Thing>> Get()
{
// The real "Thing" would be asynchronously retrieved from the DB
return Ok(new Thing());
}
}
[Fact]
public async Task Test1()
{
var controller = new ValuesController();
var actionResult = await controller.Get();
Assert.NotNull(actionResult.Value);
Assert.Equal("Foobar", actionResult.Value.Name);
}
此测试没有变为绿色,而是在 NotNull
断言上失败了(或者,如果我没有该断言,它会抛出 NullReferenceException
).
Instead of turning green, this test fails on the NotNull
assertion (or, if I would not have that assertion, it throws a NullReferenceException
).
在调试并检查了类层次结构之后,我发现这似乎可以达到预期的结果:
After debugging and inspecting the class hierarchy, I found that this seems to give the desired results:
[Fact]
public async Task Test1()
{
var controller = new ValuesController();
var actionResult = await controller.Get();
var okResult = actionResult.Result as OkObjectResult;
var realResult = okResult?.Value as Thing;
Assert.Equal("Foobar", realResult?.Name);
}
但是,感觉就像我做错了什么.实际上,我还有两个相关的问题:
But this feels like I'm doing something wrong. Practically, I'm left with two related questions:
- 是否有另一种惯用的方式编写此测试,从而将所有那些
as
强制转换折叠起来? - 第一个示例为什么要编译,却给出运行时异常?这是怎么回事?
推荐答案
对于XUnit,您可以使用 T t = Assert.IsType< T>(other)
.这将在可能的情况下进行转换,否则将导致测试失败.
With XUnit, you can use T t = Assert.IsType<T>(other)
. That will do the casting if possible, but otherwise it will cause the test to fail.
例如,我做这样的事情:
For instance I do something like this:
IActionResult actionResult = await Controller.GetItem(id);
OkObjectResult okObjectResult = Assert.IsType<OkObjectResult>(actionResult);
Model model = Assert.IsType<Model>(okObjectResult.Value);
Assert.Equal(id, model.Id);
关于第二个问题,事情可能在运行时引发空引用异常并正确编译.该问题将使用C#8和非空类型解决.
As for your 2nd question, things can throw null reference exceptions at runtime and compile correctly. That problem will be solved with C# 8 and non-nullable types.
这篇关于如何使用返回类型ActionResult< T>对动作进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!