我是测试 .net core Web API 的新手,并且正在努力测试 API 上的 POST 方法。我可以断言返回的 ActionResult 的类型,但我似乎无法弄清楚如何将结果与我正在创建的固定装置进行比较。
我已经调试了单元测试,发现 CreatedAtAction 调用返回了一个 ActionResult。顶层值为空。但是,结果的值有该项目。
我觉得我错过了演员表或其他东西,我的代码应该期待 CreatedAtActionResult 或其他东西,但我似乎不知道如何让它工作。
这是我的控制器的 (POST) 方法:
[HttpPost]
public async Task<ActionResult<TodoItem>> AddTodoItem(TodoItem item)
{
_context.TodoItems.Add(item);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}
这是我的单元测试:
[Fact]
public async Task PostTodoItem_ShouldPass()
{
var fixture = new Fixture();
var item = fixture.Create<TodoItem>();
var result = await _controller.AddTodoItem(item);
Assert.IsType<ActionResult<TodoItem>>(result); // WORKS
Assert.Equal(item, result.Value); // DOESN'T WORK!!
}
我正在使用 Autofixture 和 EF 内存数据库进行测试。所有这些都是在单元测试之前运行的共享数据库固定类中设置的。
这是我的调试器输出。
这似乎是对象模型中的一个奇怪现象。但我不知道原因。 您调用 CreatedAtAction ,它会返回 CreatedAtActionResult。它有一个 Value 属性,它是一个对象。这就是您将 TodoItem 传递到的内容,您可以在调试器输出中看到它。
这个类不继承自 ActionResult< T>,但这就是你的函数返回的内容。 ActionResult< T> 确实有一个隐式运算符,允许将任何类型转换为它,并且该运算符适用于 ActionResult 对象(非通用)。
因此,当编译器看到您返回 CreatedAtActionResult 时,它需要将其转换为 ActionResult< T> ,以便从 ActionResult 调用隐式转换(如 CreatedAtActionResult : ObjectResult : ActionResult)。
因此,要获得您想要的比较的待办事项,您需要:
Assert.Equal(item, (result.Result as CreatedAtActionResult).Value); // SHOULD WORK!!
Assert.Equal(item, result.Value); // 不起作用!!
Assert.Equal(item, ((ObjectResult)actual.Result).Value); // 试试这个应该可以工作
我将 @shrinith-sanil 答案包装到扩展中,以便轻松地在我的所有控制器中重用。谢谢!
public static class ActionResultExtensions
{
/// <summary>
/// Becuase controllers return an ActionResult instead of ObjectResult, some fancy casting must be done.
/// https://stackoverflow.com/questions/57929044/trouble-with-actionresult-in-unit-test-cant-assert-equal-on-post-return-value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
/// <returns></returns>
public static async Task<T> UnwrapAsync<T>(this Task<ActionResult<T>> task) where T : class
{
var result = await task;
var objectResult = result.Result as ObjectResult;
var value = objectResult.Value as T;
return value;
}