My question is very similar to this one:
How to unit-test an action, when return type is ActionResult?
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.
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);
}
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:
- Is there another idiomatic way to write this test, that collapses all those
as
casts? - Why does the first example compile, yet give a runtime exception? What's going on here?