美文网首页
IntelliTest(4) – Hands on[译]

IntelliTest(4) – Hands on[译]

作者: Johnny_ | 来源:发表于2018-04-10 21:51 被阅读0次

      在我们写传统单元测试时,为了达到一定的覆盖率,开发者需要反复的做一些类似的工作,比如,写测试用例,查看哪些代码未被覆盖,继续写测试用例覆盖之,直到所有的代码都被覆盖。

      有了IntelliTest后,这一切都变得不一样了。我们会手把手的介绍IntelliTest技术,为了便于大家理解,会使用一个demo项目

    一、准备demo项目

      按照上面给出的GitHub地址,克隆项目后,打开PokerLeagueManager.sln。这个demo主要用于跟踪统计每周的扑克牌联赛数据,每个玩家的游戏记录(玩过的游戏、总胜利次数、总筹码等)都会记录在一张表里。我们想要测试的方法在PokerLeagueManager.Queries.Core\EventHandlers\GetPlayerStatisticsHandler.cs\Handle
    (GameDeletedEvent)里,代码片段如下:


    image.png

    这个方法做的事情是在一次游戏结束后更新相关玩家的数据。详细步骤如下:

    1. 获取在这次游戏的相关玩家
    2. 遍历这些玩家,并获取它们当前的统计数据
    3. 更新玩家数据
    4. 保存数据

    正如我们在平时的开发,这个方法需要和其他对象交互。我们的目标就是让IntelliTest生成100%覆盖率的用例。

    二、运行IntelliTest并理解它的警告

      我们可以看到,只生成了两个用例,而且覆盖率极低(6/42blocks),还有5个警告。


    image.png

    点击警告按钮切换到警告界面。


    image.png

    第一个分类是“运行时警告”,将使用“PokerLeagueManager.Queries.Core.QueryDataStore
    [PQCQ]” 作为接口“IQueryDataStore”的实例。通过查看代码,我们发现“IQueryDataStore”在基类BaseHandler中以属性的形式定义。为了测试Handle方法,我们必须要有一个IQueryDataStore的实例,这里,IntelliTest通过探测为我们推荐了PQCQ。

    那么,PQCQ真的是我们需要的类型吗?

      与此同时,IntelliTest探测到需要有一个公开的方法来初始化PQCQ,因为我们在测试Handle方法时需要用到PQCQ的实例,所以,在第二个警告分类“对象创建”的第一个警告就告诉我们它将会自动生成的对象构造API(一个工厂方法),如果愿意,我们可以保存这个工厂方法供测试方法调用。


    image.png

    当IntelliTest按照自己的方式真实的去构造PQCQ时,它发现它无法构造,并给出了原因。这便是“对象创建”分类中的第二个警告。


    image.png

    第三个分类叫做“无法探测的代码”,只有一个警告,从旁边的堆栈中我们可以看到,是DbContext的构造函数中的一些代码无法探测(如何探测?)。无法探测代码,有两个可能的原因:

    1. 引擎无法探测那部分代码
    2. 探测那部分代码会导致系统运行缓慢

      有时候,IntelliTest探测分支需要运行非常多次的代码,甚至超过了系统为了保证性能设置的阈值。因此,它发出警告,并停止探测。

    三、提供伪对象

      在继续之前,我们需要回答一开始那个问题:

      PQCQ真的是我们需要的类型吗?

      显然它不是,为了测试Handle方法,我们需要一个IQueryDataStore的伪对象,在解决方案中,我们可以找到一个叫FakeQueryDataStore的类,这就是我们需要的伪对象。

      为了完成IntelliTest,我们需要完善PUT方法。

      点击警告按钮切换到测试窗口,全选用例并保存,然后删除掉.g.cs文件(这里面的用例并不符合我们的要求,它无法覆盖全部的代码)。剩下的GetPlayerStatisticsHandleTest.cs就是PUT方法的文件。

      在测试项目中添加PokerLeagueManager.Common.Tests的引用,并且按照下面图片的红色指示完善代码。


    image.png

      再次运行IntelliTest(点击探测窗口中的运行,或在PUT方法上运行IntelliTest)

      这次探索越界的警告就没了,我们可以看到有2个用例,4个警告。


    image.png

      查看警告我们发现,IntelliTest告诉我们它能够初始化PokerLeagueManager.Common.Tests.
    FakeQueryDataStore[PCTF],以及我们可以使用的API。
    当它使用这个API去初始化[PCTF]时,再次提示有无法探测的代码。在堆栈查看窗口中,我们可以跟踪到,无法探测的代码在GetData<T> 方法中。因为我们不是要测试这个伪对象,所以可以忽略这个异常。

      选择“对象创建”类别,忽略里面的全部异常。

      我们继续观察可以发现,在无法探测代码中,都是关于[PCTF]的,我们可以全部忽略。

      我们可以在PexAssemblyInfo.cs中看到,增加了两行。


    image.png

      再次运行IntelliTest。

      依然是两个用例,但是警告都没了。

      通过分析Handle方法,我们知道,GetData必须返回一些数据我们才能覆盖余下的代码。(目前只覆盖了15/42 blocks)。

    四、配置PUT

      在PUT中,“target”是我们要测试的类对象。分析代码发现,GetData<T>方法中的T,需要是LookupGamePlayersDto和GetPlayerStatisticsDto类型,我们需要用数据填充PCTF的实例,这里,我们可以通过PUT配置,让IntelliTest为我们生成这些数据。我们需要在PUT的签名中,添加需要IntelliTest帮忙生成的数据。我们需要两个LookupGamePlayersDto实例和一个LookupGamePlayersDto实例。同时,我们要将统计数据和第一个玩家关联起来。

    继续添加引用PokerLeagueManager.Common.DTO,同时按照下面红色指示添加代码:


    image.png

    接下来,我们需要填充target的数据:


    image.png

    执行被测方法:


    image.png

    最后,我们只需要简单的查询统计数据并对数据的字段下断言:


    image.png

    因为我们改变了PUT,所以可以删除g.cs文件。

    五、100%覆盖

      再次运行IntelliTest。这次我们可以看到所有的代码都被覆盖了(52/52 blocks),并且有7个用例,3个通过,4个失败。还有7个警告。


    image.png

    分析警告可以知道,所有的警告都跟我们要测试的Handle方法无关,果断忽略之。


    image.png

    忽略后,可以看到,在PexAssemblyInfo.cs中增加了如下内容:


    image.png

    再次运行IntelliTest。这次我们可以看到代码全被覆盖,7个用例通过3个,并且没有警告。


    image.png

    其中两个未通过是对参数e未作判空处理,一个是除数出现0的情况(当Statistics.GamesPlayed=1时),还有一个是堆栈溢出,通过跟踪代码我们可以知道详细的用例。

      至此,IntelliTest已经生成了所有用例,并发现了代码中的问题。如果我们增加更多的断言,会生成更多用例验证正确性。

    强烈建议阅读英文原文



    2017-10-20 11:43:52

    相关文章

      网友评论

          本文标题:IntelliTest(4) – Hands on[译]

          本文链接:https://www.haomeiwen.com/subject/inhohftx.html