xunit-performance 是xUnit的一个扩展, 使用它能够对.NET Core项目进行性能测试。git
官网:https://github.com/Microsoft/xunit-performancegithub
xUnit你们可能都用过,它是用来作单元测试的,它能够很快给开发人员功能是否OK的反馈。api
和xUnit同样,xUnit-Performance能够很快给出性能上的反馈。多线程
为了讲解,咱们须要准备一个须要被测试的项目和一个测试项目。框架
我使用Visual Studio 2017创建项目以后总有一些问题,不事后来我是用dotnet cli和VSCode就没有什么问题了。性能
创建项目的顺序以下:单元测试
1. 首先使用dotnet cli创建一个classlib类型的被测试项目,它的目标框架是.NET Standard 2.0:测试
这个项目里只有一个类,也就是要被测试的类:spa
这个类有三个方法,分别是使用foreach,for和Linq扩展方法的Sum对集合循环并求和。pwa
2. 使用dotnet cli创建一个console项目(若是使用VS2017的话直接建类库就能够,由于VS2017内置Test Runner),这个是测试项目,它的版本只能是2.0(多是由于我电脑sdk的版本较老):
另外还须要引用被测试项目。
3.而后,按照官方文档安装两个库。
xUnit-Performance目前还处于Beta阶段,这两个库须要按照官网的指示进行安装:
最新版的xunit.performance.api.dll, 这里用到的是MyGet: https://dotnet.myget.org/feed/dotnet-core/package/nuget/xunit.performance.api#.
而后是最新版的 Microsoft.Diagnostics.Tracing.TraceEvent, 这个使用Nuge: https://www.nuget.org/packages/Microsoft.Diagnostics.Tracing.TraceEvent
OK,如今依赖库都装好了。
性能测试和单元测试略有不一样, 性能测试是跑不少次, 而后取平均值. 同时也要考虑到内存等其它因素的影响.
在性能测试里就不须要测试功能的正确性了, 可是程序在压力下可能会产生不一样的结果, 尤为是多线程的状况. 这时你就须要写压力测试了.
而对于性能测试, 咱们只考虑速度.
因为我是用的是dotnet cli和VSCode,因此测试项目我选用的是控制台项目,它的Main方法须要这样写:
若是您能成功的使用VS2017创建测试项目,那么就不须要Main方法了,创建一个类库项目便可,直接使用VS2017的Test Runner便可。
下面咱们编写性能测试方法。
首先在测试项目创建一个类,而后作一些准备工做:
这里我准备了一个List<KeyValuePair<int, double>>,它有100000条数据,是随机生成的。
而后是测试方法,在这里咱们使用[Benchmark]替代了xUnit单元测试中的[Fact]:
xUnit.Performance的测试会跑不少次,结果是取平均值的。
这里咱们循环遍历Benchmark.Iterations,它有一个默认值,我这里默认是跑了1000次循环。
再循环里,首先您能够作一些准备工做。而后使用iteration.StartMeasurement()来开始进行测量。
只有iteration.StartMeasurement()后边的部分才会被测量,在大括号里面写被测试相关的代码就能够了。
而后在命令行输入运行测试:
测试结果以下:
提供了控制台输出,xml,csv,md输出(在项目文件夹里)。
从控制台能够看到该测试的循环跑了1000次,平均结果是0.963毫秒。
下面是csv结果的截图:
下面是md结果文件的截图:
下面是xml结果文件的截图,它里面有详细数据:
xUnit.Performance还能够添加一个内部循环属性 InnerIterationCount。先看代码,添加如下方法:
[Benchmark(InnerIterationCount = 10_000)],这里的InnerIterationCount是内部循环遍历的次数。
在StartMeasurement()以后,进行内部循环。
这样的话,外层循环的次数可能会不多,并且第一次外层循环是热身,不包括在测试结果中。
而内部循环适合于运行比较快速的代码(微秒级)。
有时确实须要这样两层循环,作一些热身工做或者须要完成不一样级别的准备工做。
而后咱们来跑测试
在结果里看到外层循环有2次的记录,可是它实际跑了3次,第一次算做热身,不作统计。
它的时间是内层循环的总和,除以10000以后,和第一个方法的结果差不太多。
我能够在方法中打印输出循环次数:
其结果以下:
能够看到确实是跑了3次,但统计了2次。
而后我再添加另外两个测试方法,分别测试另外两个方法:
运行测试:
能够看到如今这4个测试方法的结果。
看来针对List来讲foreach要比linq和for循环快。
注意foreach测试的外层循环跑了2次,而for和linq的测试循环只跑了1次,多是由于花费时间过久了吧?这个我不太肯定。
能够看到测试命令的参数 stopwatch,它应该是来自System.Diagnostics命名空间下的StopWatch类。
它有Start()和Stop()方法和一些其它属性用来统计逝去的时间。
StopWatch类是跨平台的,可是在其它系统上,它只能统计时间;而在Windows上,它还可使用内核ETW events和CPU性能计数来给您更多的数据,具体请查阅相关资料。
该库还有不少功能和命令的参数,具体请参考文档:https://github.com/Microsoft/xunit-performance
可是要注意,它仍然是beta状态,只能在MyGet而不是Nuget获取。