软件的单元测试关注是的软件最小可执行单元是否可以正常执行,可是软件是由一个个最小执行单元组成的集合体,单元与单元之间存在着种种依赖或联系,因此在软件开发时仅仅确保最小单元的正确每每是不够的,为了保证软件可以正确运行,单元与单元之间的集成测试是很是必要。
另外上一篇文章只是介绍了如何使用xUnit.net对.Net Core程序进行简单(无参)的单元测试以及计算代码的覆盖率,可是在实际的测试工做中,每每会经过语句覆盖、条件/分支覆盖(白盒)方式以及等价类、边界值等(黑盒)方式来设计测试用例,这些用例的测试的关键点在于传入测试方法的参数是不一样的,若是使用无参测试方法那么针对不一样的测试用例就须要编写大量的测试方法,这是不现实的。
本文将从如下几个方面,在单元测试的基础上介绍如何完成数据驱动测试以及代码依赖的集成测试:php
集成测试简单的理解就是在单元测试的基础上,将各个单元根据其依赖关系集成起来,检查代码是否可以正确运行,集成测试根据软件开发方式的不一样或者软件架构不一样也有不一样的集成方式,好比面向过程的设计方式和面向对象设计方式、单体架构以及微服务分布式架构等等。
本文涉及到的仅仅是面向对象编程中类与类之间依赖的集成测试。html
数据库是大部分软件系统不可缺乏的组件,因此在集成测试时与数据库集成是一种常见的测试场景,下面就开始介绍如何经过xUnit.Net来测试。
1. 编写被测试代码:
在被测试项目中引入EFCore以及相关组件:git
添加DBContext以及相应的数据操做代码:github
注:此处使用LocalDB做为数据库完成测试,若是使用SQL Server修改链接字符串便可。sql
用户仓储中实现了用户添加以及根据姓名查询的方法。
注:完成代码编写后,须要将实体代码迁移到数据库,先经过Add-Migration添加迁移代码,而后经过update-database命令将数据更新到数据库,迁移方法可参考:https://docs.microsoft.com/en-us/ef/core/get-started/full-dotnet/new-db
2.编写测试代码:数据库
测试代码也很是简单,就是建立一个SQLServer的用户仓储实例,而后经过构造的方式将其注入到UserManager类型中使用,后续UserManager的建立、查询用户的方法将经过该仓储实现。
3.测试运行结果:编程
这里的回归指的是回归测试,回归测试是指当修改了旧的代码后须要从新对旧代码进行测试确认这次修改没有影响到已有代码。通常来讲使用xUnit.Net实现的测试均是可回归的,由于测试代码不变,且测试代码能够重复执行,另外测试代码也被代码版本管理工具管理,当修改代码后从新执行全部测试方法便可。
可是与数据库相关的测试又有所区别,数据库是数据持久化工具,对数据的每一次操做都会被持久化,假设有两个测试用例,第一是添加一条数据,第二是查询这条数据的数量是否为1,那么这两个测试在第一次运行的时候是没有问题的,可是再次运行时第一个用例可能主键冲突没法被添加,或者添加成功后第二个用例查询结果为2,致使测试失败,这样的测试视为不可回归。
下面就介绍如何使用xUnit.Net实现数据库集成的回归测试:架构
要实现数据库集成测试的可回归性,其实最主要的问题在于每次执行完单元测试后数据库的状态都是不一样的,那么解决这个问题在每次执行测试前将数据库初始化是否就能够解决了呢?
看下面代码:分布式
首先为测试类添加构造方法,在构造方法中初始化数据库。微服务
而后在测试方法中添加用户数量测试断言,当添加完成用户后,应该一共存在1个用户。
执行测试方法:
不管执行多少次测试都是经过的,这意味着每次添加用户后用户数量均为1,这样就达到了测试的可回归性。
可是真实的开发过程当中,不可能只有一个测试类型,并且若是为每个测试类型都添加初始化数据库的代码,那么这些单元测试将会执行的很是慢(数据库的初始化很是耗时),那么要如何解决这个问题?
Fixture是xUnit.Net中的一项特性,它能够用来共享测试上下文,Fixture能够译为固定装置,换句话说就是把一个内容固定住,使该内容能够在被指定的范围内使用。xUnit.Net中Fixture有两种类型,分别是ClassFixture和CollectionFixture,它们对应的是在一个测试类型里面共享和一个测试类型集合中共享上下文,Fixture的做用有不少,下面将介绍如何使用Fixture来共享数据库被初始化这一状态(不须要重复初始化):
1. 建立一个Fixture类型:
Fixture其实是一个普通的C#类型,惟一须要注意的是它使用构造方法初始化数据、使用Dispose来释放或者清理数据,简单的一个Fixture类型以下:
2. 为单个类型使用ClassFixture:
从代码中能够看到经过构造方法初始化的代码已经被注释了,实现IClassFixture接口后,再次执行测试方法,能够看到测试仍然是可回归的。
3. 为多个类型使用ICollectionFixture:
首先须要在DatabaseFixture的基础上添加一个实现ICollectionFixture的类型:
两个要点分别是须要使用CollectionDefinition特性,而后类型须要实现ICollectionFixture<T>接口。
在测试类型上经过Collection特性,指定以前定义的Collection名称来应用该CollectionFixture:
而后屡次执行测试方法,能够发现测试仍然是可回归的:
注:在共享测试上下数据时(包括共享数据库数据),可能会由于测试方法执行顺序致使测试失败,可是xUnit.Net中没有提供按顺序执行实现方式,默认是按照方法命名,若是须要按照必定顺序执行测试,可参考官方的例子:https://github.com/xunit/samples.xunit/tree/master/TestOrderExamples
涉及到数据库的测试,极可能在测试以前数据库就会存在一些已有的测试数据,使用xUnit.Net来编写测试代码时,能够将测试数据的初始化放到Fixture类型中,可是要如何对这些数据进行管理呢?通常来讲使用SQL脚原本管理数据库的测试数据是一种不错的方式,由于这样测试数据与代码解耦,维护数据时仅须要维护SQL脚本文件便可。
下面就介绍一下如何在xUnit.Net中使用SQL脚本文件管理以及初始化数据:
1.建立一个SQL脚本:
注:须要将文件的“复制到输出目录”设置为“老是复制”或者“有更新复制”:
2.在Fixture类型初始化数据库时,执行SQL脚本初始化数据:
下面代码首先去Data目录下查找.sql的全部文件,而后依次执行这些SQL脚本。
3.修改测试代码(由于脚本添加了2条数据,因此指望值应该是3条):
4.执行测试:
测试成功。
文章最开始提到过,不论是白盒的覆盖测试仍是黑盒的边界/等价测试,它们最直接的体现就是“参数”,传入被测试方法的参数。而这些参数实际上就是“测试用例”,为每个测试用例编写一个测试方法是不合理的,因此须要一种方法经过变换参数来完成测试,而且尽量的重用测试代码。这就是数据驱动测试。
Theory和InlineData是xUnit.Net中提供的数据驱动(参数化)测试的功能特性,下面是一个theory以及InlineData的应用示例:
运行结果:
经过InlineData就能够轻易的将测试用例的数据应用到测试方法上,并完成指望的测试。可是当添加新的测试用例时就须要对代码文件进行修改,测试用例放置在代码中管理也不是很是方便,有没有一种能够独立管理测试用例数据的方法呢?
xUnit.Net没有提供内置的Excel数据加载功能,可是它的拓展性很好,能够经过实现DataAttribute实现一个Theory的数据源提供器:
1. 实现DataAttribute抽象类,实现Excel的Theory数据提供器:
下面是实现Excel数据加载的核心方法:
以上方法须要注意如下几点:
注:此处使用的Excel文件读取组件为:https://github.com/ExcelDataReader/ExcelDataReader
DataAttribute完整代码见:https://github.com/yqszt/xUnitTestDemo/blob/master/XUnitTestProject/ExcelDataAttribute.cs
2.使用ExcelDataAttribute:
3. 在AdditionTestCase.xls中添加测试用例数据:
注:须要将AdditionTestCase.xls的复制到输出目录属性设置为“老是复制”或“复制新文件”。
4.执行测试方法:
测试成功。
本文主要介绍了.Net Core使用xUnit.Net实现了与数据的集成测试并经过Fixture的方式实现了数据库的初始化,保证了测试的可回归性。另外还介绍了如何使用xUnit.Net来实现数据驱动测试,数据驱动测试能够简单地经过添加用例数据的方式来提升测试质量,还能够便捷的对测试用例进行管理。
本文示例代码:https://github.com/yqszt/xUnitTestDemo
参考:
https://en.wikipedia.org/wiki/Integration_testing
https://en.wikipedia.org/wiki/Data-driven_testing
https://xunit.github.io/docs/getting-started-dotnet-core#write-first-theory
http://dotnetliberty.com/index.php/2015/12/31/fast-asp-net-5-integration-testing-with-xunit/
https://github.com/MisterJames/GenFu
http://ikeptwalking.com/writing-data-driven-tests-using-xunit/
https://wandering.life/data-driven-testing-xunit-vs2017/
https://github.com/ExcelDataReader/ExcelDataReader
http://xunitpatterns.com/Testing%20With%20Databases.html
https://xunit.github.io/docs/shared-context