【问题标题】:Test calls async method which returns 'Value cannot be null'测试调用返回“值不能为空”的异步方法
【发布时间】:2017-12-06 23:07:07
【问题描述】:

我有一个异步方法,我正在尝试对其进行单元测试,特别是我想测试异步方法是否返回NoContent 响应,因为没有找到客户实体。这是有问题的方法:

    [HttpGet]
    [Route("customers/{customerNumber}")]
    public virtual async Task<IHttpActionResult> Get([FromUri] CustomerNumber customerNumber)
    {
        var customerEntitiesList = _tableStorageService.GetCustomerEntities(customerNumber);
        var customersList = customerEntitiesList.Select(customerEntity => customerEntity.PartitionKey).ToList();
        if (customersList.Any()) {
            return await Task.FromResult(Ok(customersList));
        }
        return await Task.FromResult(ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NoContent, "No content found.")));
    }

澄清一下,CustomerNumber 是一个字符串表示类,如下所示:

[DebuggerDisplay("{ToString()}")]
public class CustomerNumber
{
    public CustomerNumber(string customerNumber);

    public static bool TryParse(string customerNumber, out CustomerNumber parsedCustomerNumber);
    public override string ToString();

    public static implicit operator string(CustomerNumber customerNumber);
    public static implicit operator CustomerNumber(string customerNumber);
}

这是单元测试:

    [Test]
    public async Task Should_Return_No_Content_If_Customer_Entities_Are_Not_Found()
    {
        const string customerNumber = "WP0000000000";
        var customerEntitiesStub = new List<CustomerEntity>();
        A.CallTo(() => _tableStorageServiceDummy.GetCustomerEntities(customerNumber)).Returns(customerEntitiesStub);

        var result = await _companyController.Get(customerNumber);

        ((ResponseMessageResult)result).Response.StatusCode.Should().Be(HttpStatusCode.NoContent);
    }

当我运行这个测试时,它甚至在完成之前就失败了,并出现错误System.ArgumentNullException : Value cannot be null.。为什么会发生这种情况,我该如何解决它以便我可以断言结果?谢谢!

【问题讨论】:

  • 当前状态的问题尚不清楚,因为它不完整,需要太多问题才能阐明所问的内容。阅读How to Ask,然后提供minimal reproducible example,可用于重现您的问题,让我们更好地了解所询问的内容。
  • 实际上没有理由让操作返回任务。实际上没有任何异步操作。
  • 您还设置了模拟以期望 string 但实际方法具有 CustomerNumber 参数。开始在那里调查。由于设置不匹配,当调用 GetCustomerEntities 时,customerEntitiesList 将为空。
  • @Nkosi 不仅如此,它还不必要地包装,然后解包,然后重新包装,结果变成Task。如果该方法返回 Task 的原因(我无法想象它们都适用于 HTTP 端点),那么它仍然在做多余的工作。

标签: c# unit-testing async-await


【解决方案1】:

模拟设置为期望 string,但实际方法具有 CustomerNumber 参数。在那里开始调查。

由于设置不匹配,当调用 GetCustomerEntities 时,customerEntitiesList 将是 null

假设CustomerNumber 可以从字符串隐式转换,那么测试应该配置一个实际的CustomerNumber 实例。

[Test]
public async Task Should_Return_No_Content_If_Customer_Entities_Are_Not_Found() {
    const CustomerNumber customerNumber = "WP0000000000";
    var customerEntitiesStub = new List<CustomerEntity>();
    A.CallTo(() => _tableStorageServiceDummy.GetCustomerEntities(customerNumber)).Returns(customerEntitiesStub);

    var result = await _companyController.Get(customerNumber);

    ((ResponseMessageResult)result).Response.StatusCode.Should().Be(HttpStatusCode.NoContent);
}

在单独的不是该动作的设计中,将结果包装在任务中。目前没有理由使该操作异步。

[HttpGet]
[Route("customers/{customerNumber}")]
public virtual IHttpActionResult Get([FromUri] CustomerNumber customerNumber)
{
    var customerEntitiesList = _tableStorageService.GetCustomerEntities(customerNumber);
    var customersList = customerEntitiesList.Select(customerEntity => customerEntity.PartitionKey).ToList();
    if (customersList.Any()) {
        return Ok(customersList);
    }
    return Request.CreateErrorResponse(HttpStatusCode.NoContent, "No content found.");
}

并相应地更新测试。

【讨论】:

  • 感谢您的反馈!抱歉不清楚,事实上 CustomerNumber 是一个字符串表示类。所以设置工作正常,customerEntitiesList 是一个空列表,我将使用此信息更新问题。
  • @SirarSalih 调试时,你在被测方法中究竟在哪里得到异常。
  • @SirarSalih 在这种情况下只留下Request 您是否创建了测试请求并将其分配给控制器?
猜你喜欢
  • 1970-01-01
  • 2015-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
  • 2013-06-13
  • 2013-02-14
  • 2014-10-22
相关资源
最近更新 更多