Nunit里提供了丰富的数据测试功能,虽然Xunit里提供的比较少,但是也能满足很多场景下使用了,如果数据场景非常复杂,Nunit和Xunit都是无法胜任的,有不少测试者选择自己编写一个数据提供程序,但是更建议使用AutoFixture框架,一是因为自己工作中写的往往只是为了解决某个或者部分问题,只能随着业务逻辑的扩展才能不断的健壮起来,二是这样的框架往往缺少良好文档,主要由核心开发者口口相传,这就导致后来者遇到不明白了功能就去问核心开发者,影响这些开发者的其它工作.
下面介绍一下Xunit里的数据提供方式.
InlineDataInlineData相当于Nunit里的TestCase,用注解的方式给测试方法提供数据.
我们通过以下代码片段了解它的基本用法
以上方法与普通测试方法相比最大的区别是它使用的是Theory注解,而不是fact注解.使用Theory注解的方法必须提供相应的参数,否则会报编译错误.
以上测试我们提供了两组InlineData,这样在测试运行的时候测试方法就会根据这些数据生成两个方法实例.同Nunit里的表现行为相似.
MemberDataMemberData顾名思义,就是成员数据,它类似于Nunit里的TestCaseSource但是不同的是Xunit的MemberData的数据提供者必须是当前测试类的成员,测试数据提供者和测试方法耦合在一块可能不是太好的设计,如果需要大量测试数据,建议使用AutoFixture.
数据提供者之属性提供数据通过属性提供测试数据适应于一些比较简单的场景,这些数据是简单的,确定的.
下面看一个示例
以上代码中,测试方法和数据提供者必须位于同一个类中,并且数据提供者必须是一个公开的,静态的属性.并且它的集合元素类型必须是Object类型.像以上Test1方法虽然需要的是int类型参数,但是提供者类型也必须是object类型,而不能是具体类型.
以上数据提供属性一共yield了三组数据,因此测试方法会生成三个测试实例.
数据提供者之方法提供数据 [Theory] [MemberData(nameof(UnitTest1.ProvideData))] public void Test1(int x,int y) { int result = x + y; Assert.Equal(x + y, result); } public static IEnumerable<object[]> ProvideData() { yield return new object[]{3,4 }; yield return new object[] {5, 9}; yield return new object[] { 11, 13 }; }你可能会感觉以上方法和属性并没太大的区别,其实方法的功能更为强大,因为属性无法动态指定参数,而方法可以,我们可以指定方法接收动态运行时需要的参数,然后在MemberData的构造函数里传入参数来动态获取数据.
数据提供者之成员提供数据成员提供数据可以把外部对象作为本类成员,然后给测试方法提供数据.外部对象须继承自TheoryData.
我们定义一个MyDataprovider
public class MyDataprovider<TData1,TData2>:TheoryData<TData1,TData2> { public MyDataprovider(IEnumerable<TData1> dataSource1,IEnumerable<TData2> datasource2) { if (dataSource1 == null || datasource2 == null || !dataSource1.Any() || !datasource2.Any()) throw new Exception("集合不为能空或者null"); foreach (TData1 data1 in dataSource1) { foreach (TData2 data2 in datasource2) { Add(data1, data2); } } } }我们再看测试类
public class UnitTest1 { public static MyDataprovider<int, int> myprovider = new MyDataprovider<int, int>(new[] {3, 4, 5}, new[] {6, 7, 8}); [Theory] [MemberData(nameof(UnitTest1.myprovider))] public void Test1(int x,int y) { int result = x + y; Assert.Equal(x + y, result); } }我们在new MyDataprovider的时候通过构造函数传入两个集合,MyDataprovider继承了TheoryData的Add方法,把数据添加到theorydata中.
以上方法实际上生成了一个笛卡尔集{{3,6},{3,7},{3,8},{4,6},{4,7},{4,8},{5,6},{5,7},{5,8}}类似于Nunit里的values注解不加sequential,这个行为很多时候可能并不是我们想要的,我们想要的可能是{{3,6},{4,7},{5,8}}这样的组合,这其实是可以在MyDataprovider里自定义的.
我们把MyDataprovider改为如下就可以了
这样虽然可以把数据提供者转移到外部了,然而去把简单的问题搞的相当复杂!
数据提供者之类数据提供者