使用xUnit为.net core程序进行单元测试(4)
第1部分: http://www.cnblogs.com/cgzl/p/8283610.html
第2部分: http://www.cnblogs.com/cgzl/p/8287588.html
第3部分: http://www.cnblogs.com/cgzl/p/8438019.html
请使用这个项目的代码: https://pan.baidu.com/s/1i7d8z2H
数据驱动的测试
打开PlayerCharacterShould.cs
添加几个Fact测试方法:
[Fact]
public void TakeZeroDamage()
{
_sut.TakeDamage();
Assert.Equal(, _sut.Health);
} [Fact]
public void TakeSmallDamage()
{
_sut.TakeDamage();
Assert.Equal(, _sut.Health);
} [Fact]
public void TakeMediumDamage()
{
_sut.TakeDamage();
Assert.Equal(, _sut.Health);
} [Fact]
public void TakeMinimum1Damage()
{
_sut.TakeDamage();
Assert.Equal(, _sut.Health);
}
Build, Run tests. 都Pass了.
仔细看下这4个方法, 他们其实是做了同样的事情, 只不过输入的数据和期待的结果不同而已.
所以我们应该重构一下这段代码.
Theory:
针对上述情况, 我们就不再使用Fact属性标签了, 而是需要使用Theory.
Theory标签会告诉xUnit, 它下面的测试方法会被执行多次, 而每次执行必须为这个方法提供必要的测试数据.
如何为其添加测试数据呢? 首先要为测试方法添加参数, 使用参数来代替具体的数值:
[Theory]
public void TakeDamage(int damage, int expectedHealth)
{
_sut.TakeDamage(damage);
Assert.Equal(expectedHealth, _sut.Health);
}
然后我们需要告诉xUnit这个测试方法的参数来自哪里.
1. 最简单的办法是使用InlineData属性标签:
[Theory]
[InlineData(0, 100)]
[InlineData(1, 99)]
[InlineData(50, 50)]
[InlineData(101, 1)]
public void TakeDamage(int damage, int expectedHealth)
{
_sut.TakeDamage(damage);
Assert.Equal(expectedHealth, _sut.Health);
}
上面我添加了四组测试数据, 每对数据按顺序对应测试方法的两个参数. (InlineData的参数类型是params object[])
然后Build, 查看Test Explorer:

会发现这里面多出来了4个测试, 分别对应那4个InlineData.
Run Tests, 都会Pass的.
现在就可以把那四个Fact测试方法删除了.
尽管InlineData使用起来还是很方便, 但是在某些情境下还是灵活性欠佳, 请您查看NonPlayerCharacterShould.cs里面的代码. 取消里面的注释:
namespace Game.Tests
{
public class NonPlayerCharacterShould
{
[Theory]
[InlineData(, )]
[InlineData(, )]
[InlineData(, )]
[InlineData(, )]
public void TakeDamage(int damage, int expectedHealth)
{
NonPlayerCharacter sut = new NonPlayerCharacter(); sut.TakeDamage(damage); Assert.Equal(expectedHealth, sut.Health);
}
}
}
首先Build, Run Tests, 都Pass.
这个Theory的四组参数和上面的是一样的.
2.为了共享这几组测试数据, 可以使用MemberData属性标签, 首先创建一个类InternalHealthDamageTestData.cs:
namespace Game.Tests
{
public class InternalHealthDamageTestData
{
private static readonly List<object[]> Data = new List<object[]>
{
new object[] {, },
new object[] {, },
new object[] {, },
new object[] {, }
}; public static IEnumerable<object[]> TestData => Data;
}
}
这里面的数据和之前的那四组数据是一样的.
然后修改NonPlayerCharacterShould里面的代码, 把InlineData都去掉:
namespace Game.Tests
{
public class NonPlayerCharacterShould
{
[Theory]
[MemberData(nameof(InternalHealthDamageTestData.TestData), MemberType = typeof(InternalHealthDamageTestData))]
public void TakeDamage(int damage, int expectedHealth)
{
NonPlayerCharacter sut = new NonPlayerCharacter(); sut.TakeDamage(damage); Assert.Equal(expectedHealth, sut.Health);
}
}
}
这里改成了MemberData, 它的参数很多, 第一个参数是数据提供类的属性名字, 这个属性类型要求是IEnumberable的, 所以这里应该写"TestData", 不过最好还是使用nameof, 这样如果更改了数据类的属性名称, 那么编译时就会报错, 而不会导致测试失败.
然后还需要设置MemberType属性, 表明数据提供类的类型.
Clean Solution, Build, 可以看到还是有4个测试, Run Tests, 都会Pass的.
针对PlayerCharacterShould, 也这样修改. 这样测试数据就得到了共享.
3. 外部数据.
查看一下项目里面的TestData.csv: 里面还是这四组数据:
,
,
,
,
再创建一个类ExternalHealthDamageTestData.cs来取出csv中的数据:
namespace Game.Tests
{
public class ExternalHealthDamageTestData
{
public static IEnumerable<object[]> TestData
{
get
{
string[] csvLines = File.ReadAllLines("TestData.csv");
var testCases = new List<object[]>();
foreach (var csvLine in csvLines)
{
IEnumerable<int> values = csvLine.Split(',').Select(int.Parse);
object[] testCase = values.Cast<object>().ToArray();
testCases.Add(testCase);
}
return testCases;
}
}
}
}
修改一下NonPlayerCharacterShould和PlayerCharacterShould相关测试方法的属性标签:
namespace Game.Tests
{
public class NonPlayerCharacterShould
{
[Theory]
[MemberData(nameof(ExternalHealthDamageTestData.TestData), MemberType = typeof(ExternalHealthDamageTestData))]
public void TakeDamage(int damage, int expectedHealth)
{
NonPlayerCharacter sut = new NonPlayerCharacter(); sut.TakeDamage(damage); Assert.Equal(expectedHealth, sut.Health);
}
}
}
[Theory]
[MemberData(nameof(ExternalHealthDamageTestData.TestData), MemberType = typeof(ExternalHealthDamageTestData))]
public void TakeDamage(int damage, int expectedHealth)
{
_sut.TakeDamage(damage);
Assert.Equal(expectedHealth, _sut.Health);
}
Build, 查看Test Explorer:

针对他们中的任意一个类, 只能发现一个相关的测试, 而不是四个测试.
Run Tests的话, 会报错:

它找不到TestData.csv, 这是因为我们需要更改一下csv文件的属性, 把它改成Copy always:

然后选择Rebuild Solution, 这样才能保证csv文件被copy到正确的位置.
再查看Test Explorer:

这时就会看到4组测试了, Run Tests, 都会Pass的.
如果再添加一组数据, 还是需要Rebuild Solution的, 然后新的测试会出现在Test Explorer里面.
4.CustomDataAttribute 自定义数据属性标签.
使用自定义的标签可以把测试数据在test case和class之间共享, 而且会提高测试的可读性.
建立一个类 HealthDamageDataAttribute.cs:
namespace Game.Tests
{
public class HealthDamageDataAttribute : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return new object[] { , };
yield return new object[] { , };
yield return new object[] { , };
yield return new object[] { , };
}
}
}
这里需要实现xUnit的DataAttribute这个抽象类.
修改NonPlayerCharacterShould和PlayerCharacterShould的相关方法, 把上面的自定义标签写上去:
namespace Game.Tests
{
public class NonPlayerCharacterShould
{
[Theory]
[HealthDamageData]
public void TakeDamage(int damage, int expectedHealth)
{
NonPlayerCharacter sut = new NonPlayerCharacter(); sut.TakeDamage(damage); Assert.Equal(expectedHealth, sut.Health);
}
}
}
Build, 然后再Test Explorer还是可以看到四组测试, 如果再想添加一组测试, 只需重新Build即可.
测试同样都会Pass的.
同样自定义标签可以整合外部数据, 这个很简单, 您自己来写一下吧.
这个xUnit简介就到此为止了, 想要深入了解的话, 还是看官方文档吧.
使用xUnit为.net core程序进行单元测试(4)的更多相关文章
- 使用xUnit为.net core程序进行单元测试(上)
一. 导读 为什么要编写自动化测试程序(Automated Tests)? 可以频繁的进行测试 可以在任何时间进行测试,也可以按计划定时进行,例如:可以在半夜进行自动测试. 肯定比人工测试要快. 可以 ...
- 使用xUnit为.net core程序进行单元测试(1)
导读 为什么要编写自动化测试程序(Automated Tests)? 可以频繁的进行测试 可以在任何时间进行测试,也可以按计划定时进行,例如:可以在半夜进行自动测试. 肯定比人工测试要快. 可以更快速 ...
- 使用xUnit为.net core程序进行单元测试(中)
第一部分: http://www.cnblogs.com/cgzl/p/8283610.html 下面有一点点内容是重叠的.... String Assert 测试string是否相等: [Fact] ...
- 使用xUnit为.net core程序进行单元测试(3)
第1部分: http://www.cnblogs.com/cgzl/p/8283610.html 第2部分: http://www.cnblogs.com/cgzl/p/8287588.html 请使 ...
- 使用xUnit为.net core程序进行单元测试 -- Assert
第一部分: http://www.cnblogs.com/cgzl/p/8283610.html Assert Assert做什么?Assert基于代码的返回值.对象的最终状态.事件是否发生等情况来评 ...
- 使用xUnit为.net core程序进行单元测试(2)
第一部分: http://www.cnblogs.com/cgzl/p/8283610.html 下面有一点点内容是重叠的.... String Assert 测试string是否相等: [Fact] ...
- 使用xUnit为.net core程序进行单元测试
第1部分: http://www.cnblogs.com/cgzl/p/8283610.html 第2部分: http://www.cnblogs.com/cgzl/p/8287588.html ...
- 好代码是管出来的——.Net Core中的单元测试与代码覆盖率
测试对于软件来说,是保证其质量的一个重要过程,而测试又分为很多种,单元测试.集成测试.系统测试.压力测试等等,不同的测试的测试粒度和测试目标也不同,如单元测试关注每一行代码,集成测试关注的是多个模块是 ...
- .NET Core: 在.NET Core中进行单元测试
单元测试能够帮助开发人员确保所开发的模块.类以及类中的方法等的正确性,在项目开发过程中,及时进行单元测试能够避免不必要的BUG以及提高测试效率. 在本文中,我们会分别来学习如何使用MSTest.xUn ...
随机推荐
- 配置 java web Tomcat
index.jsp-->换为默认的MyEclipse JSP Editor打开方法:window -->Preference-->general-->editors--> ...
- 将电脑文件复制到vm虚拟机中,然后安装步骤
[root@lixiaohu 桌面]# cp openssl-1.0.1f.tar.gz /usr/src /usr/src 这是复制到的路径[root@lixiaohu 桌面]# cd / ...
- 用 Deployment 运行应用 - 每天5分钟玩转 Docker 容器技术(123)
从本章开始,我们将通过实践深入学习 Kubernetes 的各种特性.作为容器编排引擎,最重要也是最基本的功能当然是运行容器化应用,这就是本章的内容. Deployment 前面我们已经了解到,Kub ...
- [学习OpenCV攻略][006][平滑图片]
cvCreateImage(图片大小,像素位数,通道数) 创建图片,根据输入的图片大小,各个通道像素点的位数,和通道数.像素点宏IPL_DEPTH_8U cvGetSize(图片) 得到图片的大小信息 ...
- 如何为图片添加热点链接?(map + area)
所谓图片热点链接就是为图片指定一个或多个区域以实现点击跳转到指定的页面.简单来说就是点击某一区域就能跳转到相应的页面,而无需点击整个图片才能跳转. 说到图片热点链接,我首先想到了map + area, ...
- 关于responseBody注解中文乱码的问题解决
在web.xml中定义字符集过滤器: <filter> <filter-name>SpringEncodingFilter</filter-name> <fi ...
- python 模块中的 __init__.py __main__.py
python中文件夹想作为一个模块被引用,则在文件夹内必须要包含 __init__.py 文件,即使此文件为空. 如果此模块想要运行则必须要包含 __main__.py 文件.接下来说下两个文件起到的 ...
- Centos6.9安装Node.js+npm爬坑
Node.js选择 1.下载 wget https://nodejs.org/dist/v8.4.0/node-v8.4.0-linux-x86.tar.gz 2.解压 tar zxvf node-v ...
- Java泛型类和泛型方法
java编程思想说道: 泛型类是应用在整个类上,但同时可以在类中包含参数化方法,而这个方法所在的类可以是泛型,也可以不是泛型,也就是说是否有泛型方法,与其所在的类是否是泛型类没有关系. 泛型方法是的该 ...
- MYsql优化where子句
该部分讨论where子句的优化,不仅select之中,相同的优化同样试用与delete 和update语句中的where子句: 1: 移去不必要的括号: ((a AND b) AND c OR ((( ...