在进行单元测试的时候,很多时候,很多时候我们都是在单元测试方法内部提供特定的值,但是这样测试往往造成样本数不足从而导致覆盖的结果不够全面,很多时候我们更想提供来自外部的,满足条件的一组值来进行测试.其实Nunit框架本身提供了为测试用例提供值的能力.我们可以对它进行扩展来实现导入外部的值来填充到测试方法内部.很多朋友也自己写了不少按照一定规则生成值的方法.但是往往都是在方法内部直接调用,这样就会和单元测试的逻辑混杂在一块,导致测试方法本身不够简洁.其实可以根本测试框架本身的能力改造成为注解的方式,这样参数生成逻辑和测试逻辑一目了然.后面我们还会讲解基于Autofixture框架来生成填充数据,autofixture相比我们自己写的值填充方法,往往功能更加强大.后面我们将见证其强大之处.
提供普通参数很容易发现,单元测试的方法都是不带参数的,有些时候我们需要为一个要测试的方法(并非单元测试方法)提供多个参数进行测试,这就会导致一个问题:我们需要写很多类似的测试方法,只是参数不一样,这样维护起来不方便,同时大量重复的工作也很烦.下面介绍Nunit里如何为测试提供参数
int Add(int x, int y) { return x + y; }以上是我们要测试的方法.
虽然Nunit测试方法正常情况下是不支持参数的,但是如果对参数添加的values注解,Nunit便会把这些参数应用到测试.
我们看一下编写的测试方法
我们运行以上方法,可以看到测试结果通过,但是我们看一下测试面板(Test Explorer)
通过截图我们很容易发现,这个测试方法一共运行的九次!再仔细看看方法对应的参数,可以看到它是使用组合的方式把所有的可能都组合一遍.
但是有些时候我们想要的不是这样的组合,我们想要的更多时候是(3,6),(4,7),(5,8)这样的组合,如何做到呢,仍然看一段示例代码
[Test] [Sequential] public void DemoTest([Values(3,4,5)]int a,[Values(6,7,8)]int b) { var result = Add(a, b); Assert.AreEqual(a + b, result); }我们看看运行结果
这次只运行了三次,并且参数的组合正如我们期待的.
这个方法和上面的一样,只是多了一个[Sequential]注解
注意Values注解里的参数都是Object类型,运行时候转换为参数的真正类型,如果无法转换则会抛出异常.比如[Values("a")]int x由于a是字符串类型,通过内置方法无法转换为int,因些会抛出异常.
提供基于范围的参数上面的测试Values(3,4,5)和Values(6,7,8)都是连续的数字,如果连接的参数更多,我们可以使用基于范围的参数.
看以下示例代码
[Test] [Sequential] public void DemoTest([Range(3,5)]int a,[Range(6,8)]int b) { var result = Add(a, b); Assert.AreEqual(a + b, result); }我们把Values注解改为Range注解,就ok了
提供随机参数我们还可以为测试提供一些随机数,以使测试变得更随机,覆盖范围更大
这里要使用Random注解
请看下面示例
Random的参数为要生成随机数的个数.
Random还有一重载以支持生成随机数的最大值和最小值
[Test] [Sequential] public void DemoTest([Random(3,10,2)]int a, [Random(5,9,3)]int b) { var result = Add(a, b); Assert.AreEqual(a + b, result); }示例中Random的三个参数分别是最小值,最大值和个数
[info]Random的最大值和最小值不仅可以是整数,也可以是小数
提供计算参数先看一个示例
[Test] [Sequential] public void DemoTest(DateTime dt1) { DateTime dt2 = default(DateTime); Assert.Greater(dt1, dt2); }这里测试方法的参数是Datetime类型,我们如何给给它提供值呢,很多人可能会想使用Values[DateTime.Now] 来注解dt1参数,然而不幸的是Values注解只接受const类型的值,这里介绍ValueSource注解来解决这个问题.
ValueSource的机制是使用一个方法来获取值,然后提供给测试方法参数,它接受一个字符串类型的参数,用于指定提供值的方法名.
我们用以下方法生成一些DateTime值
static IEnumerable<DateTime> GetPeople() { yield return DateTime.Now; yield return DateTime.Now.AddDays(2); }