.NET单元测试(五):多线程

鉴于.NET Framework 4.5后.NET增加了对 async/await 的支持,本文讨论的异步内容均基于async/await

  客户端界面开发,多线程是逃不了的话题,而多线程的加入势必对程序的稳定性带来挑战,单元测试就显得更为重要。相对于同步代码的测试,多线程单元测试有更多细节需要注意。

async void 和 async Task。

  假设某一天你运气不好,需要为类似如下的方法补充单元测试:

public static bool Changed;

public static async void ChangeAsync()
{
    await Task.Run(() =>
    {
        Task.Delay(1000);
        Changed = true;
    });
}

你发现,要测试此方法需要用一些奇葩的方式,比如:

[TestMethod()]
public void ChangeAsyncTest_OriginalFalse_ChangeToTrue()
{
    AsyncClient.Changed = false;

    AsyncClient.ChangeAsync();
    Thread.Sleep(1100);

    Assert.IsTrue(AsyncClient.Changed);
}

显然,这种延时等待是极其恶心的,如果ChangeAsync方法返回的不是void而是Task,我们就可以愉快的await了:

[TestMethod()]
public async Task ChangeAsyncTest_OriginalFalse_ChangeToTrue()
{
    AsyncClient.Changed = false;

    await AsyncClient.ChangeAsync();

    Assert.IsTrue(AsyncClient.Changed);
}

需要特别注意的是,在异步单元测试方法中也必须返回Task,这是MSTest的约定,否则这个测试方法无法运行起来。(实际上MSTest也需要使用返回的Task来收集异常,关于这部分更多内容可以参见Async/Await最佳实践

抛弃ExpectedException

  在测试程序是否按照预期的抛出了异常,我们常常会用ExpectedException,这家伙有一个问题,它是对整个测试方法的方法体做捕获,也就是说测试方法中的非action代码抛出了异常依然能够被ExpectedException捕获,这就造成潜在的bug,为了解决此问题,在MSTest V2之前往往需要写一些辅助方法,但MSTest V2断言库中增加了Assert.ThrowsExceptionAsync和Assert.ThrowsException,可以精确的定位在哪段代码中抛出了异常。假设我们的被测代码跟下面类似:

public static async Task ChangeAsync()
{
    await Task.Run(() =>
    {
        throw new InvalidOperationException();
    });
}

测试代码可以这样写:

[TestMethod()]
public async Task ChangeAsyncTest_ThrowInvalidOperationException()
{
    await Assert.ThrowsExceptionAsync<InvalidOperationException>(async () =>
    {
        await AsyncClient.ChangeAsync();
    });
}

异步方法mock

  在moq中,异步方法的mock也是极其简单的,假设有这样的接口:

public interface ITextReader
{
    Task<string> ReadTextAsync();
}

测试代码中mock其返回结果可以有如下两种写法:

var mockTextReader = new Mock<ITextReader>();

//可以这样
mockTextReader.Setup(x => x.ReadTextAsync()).Returns(async ()=>await Task.FromResult("mockValue"));

//也可以这样
mockTextReader.Setup(x => x.ReadTextAsync()).ReturnsAsync(()=> "mockValue");



2017-11-30 15:26:34

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 前言 在之前的系列博客中,主要围绕的是测试工具的介绍与使用。经过几个月的沉寂,在项目中摸索与实践单元测试,曾经踩坑...
    水木飞雪阅读 7,878评论 0 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,159评论 19 139
  • 什么是单元测试 在计算机编程中,单元测试(Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最...
    HelloCsl阅读 13,750评论 1 46
  • 本文主要介绍了在 C# 中使用 Async 和 Await 关键字进行异步编程的心得,是入门级的学习笔记。 题解:...
    BossOx阅读 11,057评论 4 27
  • 除去所有浪漫的惊喜和冗杂的情话,也许爱情只是一段尽可能长久的陪伴,长到四季穿过蒹葭,长到青丝抽离成...
    末欢阅读 4,894评论 0 3

友情链接更多精彩内容