【问题标题】:How to Unit test an AsyncTask which await another Async task?如何对等待另一个异步任务的 AsyncTask 进行单元测试?
【发布时间】:2017-07-15 01:12:23
【问题描述】:
public async Task<ResModel> GetDetails()
{
    ResModel resp = new ResModel();
    resp = await MobController.GetAllDeatails();
    return resp;
}

await 中,这会调用一个名为GetAllDeatails 的异步任务方法并返回一个对象ResModel

如何为此正确创建单元测试?

我创建的单元测试就在下面:

[TestMethod]
public async Task GetFromGetDetails()
{
    var controller = new SevicesController();
    ResModel resp = new ResModel();

    using(ShimsContext.Create())
    {
        ProjectAPI.Fakes.ShimMobController.GetAllDeatails = () => {
            resp.MessageType = "Get"
            resp.Message ="contdetail";

            return resp;
        };

        returnValueOfAsyncTask = await controller.GetDetails();

        Assert.IsNotNull(returnValueOfAsyncTask);
    }

}

这会在创建 ShimContext 时出错,因为在 GetAllDeatails 中返回类型必须是异步的,但这里它只返回对象。

以下是我得到的主要错误:

错误 CS0029 无法隐式转换类型 'ProjectAPI.Models.ResModel''System.Threading.Tasks.Task&lt;ProjectAPI.Models.ResModel&gt;' Un‌​itTestProjectAPI

【问题讨论】:

  • 亲爱的@BartoszKP 我已经编辑了这个问题。并按照您的建议缩小范围。问题必须与创建为 ProjectAPI.Fakes.ShimMobController.GetAllDeatails 的假方法有关。因为这必须返回一个 Async 对象。但这里它只返回一个对象。
  • 谢谢,这样好多了。但是,最好将错误消息粘贴到帖子中,这样就完全清楚您在说什么错误:)
  • 感谢@BartoszKP 错误 CS0029 无法将类型 'ProjectAPI.Models.ResModel' 隐式转换为 'System.Threading.Tasks.Task' UnitTestProjectAPI 是我得到的主要错误。问题一定是我创建为假的返回类型与给定的 AsyncTask 方法之间的差异。任何想法......?

标签: asp.net unit-testing async-await microsoft-fakes shim


【解决方案1】:

错误消息明确指出它无法将ResModel 转换为Task&lt;ResModel&gt;,这是正在填充的方法的返回类型。

在 shim 中,当方法假定返回任务时,您将返回模型。使用Task.FromResult 将模型包装在任务中,以便它可以返回并等待。

在执行被测方法时,您声明用于保存等待结果的变量是Task&lt;ResModel&gt;。这应该改变,因为当你await一个返回结果的任务时,它只会返回结果而不是任务。因此需要将结果变量从Task&lt;ResModel&gt; 更改为ResModel

这是基于上述更改的更新单元测试。

[TestMethod]
public async Task GetFromGetDetails() {
    //Arrange
    var controller = new SevicesController();
    var expected = new ResModel();

    using(ShimsContext.Create()) {

        ProjectAPI.Fakes.ShimMobController.GetAllDeatails = () => {
            expected.MessageType = "Get"
            expected.Message ="contdetail";

            return Task.FromResult(expected); 
        };

        //Act
        var actual = await controller.GetDetails();

        //Assert
        Assert.IsNotNull(actual);
        Assert.AreEqual(expected, actual);
    }
}

【讨论】:

  • 亲爱的@Nkosi 感谢您在这里的快速回答。我也试过了。但在 returnValueOfAsyncTask = await controller.GetDetails() as Response; 行的行给出了相同的上述错误。有什么建议?但这将我缩小到一行谢谢。
  • @TharushaShehan returnValueOfAsyncTask 是什么类型,错误信息到底是什么?
  • 亲爱的@Nkosi 该错误与上面的错误相同。 错误 CS0029 无法将类型 'ProjectAPI.Models.ResModel' 隐式转换为 'System.Threading.Tasks.Task' Un‌​itTestProjectAPI 现在它只给出了我在评论。至于 returnValueOfAsyncTask ** 是我作为单元测试断言的变量,它是一个 **Task
  • 这就是问题所在。当您使用 await 它返回 ResModel 而不是任务
  • 亲爱的@Nkosi 再次感谢。哇,这成功了并构建了代码,非常感谢。但这会发出警告说 此异步方法缺少“等待”运算符,并将同步运行。考虑使用 'await' 运算符来等待非阻塞 API 调用,或使用 'await Task.Run(...)' 在后台线程上执行 CPU 密集型操作。 您也可以为此提出解决方案吗?
【解决方案2】:

更改方法返回类型 到

(公共异步任务 GetFromGetDetails()

【讨论】:

  • 那是测试方法。没有必要改变它。
  • 亲爱的@Shoba 感谢您的回答。但我无法更改源代码。它与许多其他功能相连。所以我不能仅仅为了测试目的而改变它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 2019-12-12
  • 2017-06-01
  • 1970-01-01
相关资源
最近更新 更多