【问题标题】:Unit test for controller doesn't work as expected控制器的单元测试无法按预期工作
【发布时间】:2022-01-19 23:53:55
【问题描述】:

我创建了以下控制器:

[HttpGet(“{provId}/m”)]
public async Task<IActionResult> GetMForProv (int provId)
{
   var result = await _mediator.Send(new GetMForProvQuery() { ProvId = provId });

   if (result == null)
   {
      return NotFound();
   }

   return Ok(result);
}

还有下面的单元测试:

public class GetMForProvTest
{
   private readonly ProvController _sut;
   private readonly Mock<IMediator> _mediator;
   private readonly Mock<IConfiguration> _configuration;

   public GetMForProvTest()
   {
      _mediator = new Mock<IMediator>();
      _configuration = new Mock<Iconfiguration>();

      _mediator.Setup(x => x.Send(It.IsAny<GetMForProvQuery>(), It.IsAny<CancellationToken>()))
           .ReturnsAsync(new CatDto());

      _sut = new ProvController(_mediator.Object, _configuration.Object);
   }

   [Fact]
   public async Task ShouldReturnNotFoundResult_AfterGetMForProv()
   {
      var result = await _sut.GetMForProv(123); // this providerId does not exist

      Assert.Equal(StatusCodes.Status404NotFound, (result as NotFoundObjectResult).StatusCode);
   }

当我运行上述测试时,在Assert.Equal(…) 行上我得到

对象引用未设置为对象的实例。

(... 因为 NotFoundObjectResult 返回 null。

我怎样才能得到这项工作?

【问题讨论】:

  • 你有更完整的堆栈跟踪,以便我们可以看到抛出异常的位置吗?
  • ReturnsAsync(new CatDto()); 设置为返回一个对象。所以 if (result == null) 将是 false 并且 Ok 将被返回。 OkResult 无法转换为 NotFoundResult 这就是您收到错误的原因。更改为ReturnsAsync(null); 以解决问题。
  • @Chetan ReturnsAsync(null) 不工作。 VS 表示“以下方法和属性之间的调用不明确:'ReturnsExtensions.ReturnsAsync (IReturns >, TResult)”和 'ReturnsExtensions.ReturnsAsync(IReturns >, Func)'”
  • 我认为您需要强制转换为 NotFoundResult 而不是 NotFoundObjectResult。 docs.microsoft.com/en-us/dotnet/api/…
  • 我已经尝试并得到相同的 Intellisense 错误“调用不明确......”我也尝试过 ReturnsAsync((CatDto)null)ReturnsAsync(default(CatDto))ReturnsAsync(() =&gt; null),但我得到了“未设置对象引用...... ”

标签: c# unit-testing asp.net-core .net-core asp.net-core-webapi


【解决方案1】:

答案由 cmets 中的 Chetan 提供:

我认为您需要转换为 NotFoundResult 而不是 NotFoundObjectResult

您没有在return NotFound() 中传递对象,因此您应该改用NotFoundResultAs 运算符返回 null,这就是您收到异常的原因。将断言更新为:

Assert.Equal(StatusCodes.Status404NotFound, (result as NotFoundResult).StatusCode);

这已经过测试,并且正在使用您的原始设置为我工作:

_mediator.Setup(x => x.Send(It.IsAny<GetMForProvQuery>(), It.IsAny<CancellationToken>()))
         .ReturnsAsync(() => null);

在澄清您使用可选参数之前的原始答案

您确定为_mediator.Send 设置了正确的重载吗?看起来您正在为Send 设置不同的重载:

_mediator.Setup(x => x.Send(It.IsAny<GetMForProvQuery>(), It.IsAny<CancellationToken>()))...

需要 2 个参数。但是,您在控制器中使用单个参数调用它:

var result = await _mediator.Send(new GetMForProvQuery() { ProvId = provId })

您能否尝试设置单参数重载并传递一个返回 null 的操作:

_mediator.Setup(x => x.Send(It.IsAny<GetMForProvQuery>()))
           .ReturnsAsync(() => null);

【讨论】:

  • Intellisense 不允许我使用这个,因为它说“表达式树可能不包含使用可选参数的调用或调用”
  • 它是否适用于您的原始设置但使用:.ReturnsAsync(() =&gt; null)@Homeboy53
  • 是的,看看我在原帖中的最后一条评论。所以,我得到“未设置对象引用……”
  • 它不起作用。很抱歉我的信息令人困惑。
  • @Homeboy53 我已经测试过了——Chetan 的评论是正确的——使用NotFoundResult 而不是NotFoundObjectResult。演员表失败了,这就是你得到异常的原因。更新了我的答案
【解决方案2】:

尝试修复线路:

.ReturnsAsync(new CatDto());

.ReturnsAsync((CatDto)null);

因为你返回 CatDto 对象,而转换结果 (result as NotFoundObjectResult) 为空

【讨论】:

  • 我已经进行了更改,但我得到了相同的未设置对象引用...
猜你喜欢
  • 2021-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多