博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用xUnit为.net core程序进行单元测试(4)
阅读量:6232 次
发布时间:2019-06-21

本文共 6430 字,大约阅读时间需要 21 分钟。

第1部分: 

第2部分: 

第3部分: 

请使用这个项目的代码: 

数据驱动的测试

打开PlayerCharacterShould.cs

添加几个Fact测试方法:

[Fact]        public void TakeZeroDamage()        {            _sut.TakeDamage(0);            Assert.Equal(100, _sut.Health);        }        [Fact]        public void TakeSmallDamage()        {            _sut.TakeDamage(1);            Assert.Equal(99, _sut.Health);        }                [Fact]        public void TakeMediumDamage()        {            _sut.TakeDamage(50);            Assert.Equal(50, _sut.Health);        }        [Fact]        public void TakeMinimum1Damage()        {            _sut.TakeDamage(101);            Assert.Equal(1, _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(0, 100)]        [InlineData(1, 99)]        [InlineData(50, 50)]        [InlineData(101, 1)]        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
Data = new List
{ new object[] {
0, 100}, new object[] {
1, 99}, new object[] {
50, 50}, new object[] {
101, 1} }; public static IEnumerable
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: 里面还是这四组数据:

0, 1001, 9950, 50101, 1

再创建一个类ExternalHealthDamageTestData.cs来取出csv中的数据:

namespace Game.Tests{    public class ExternalHealthDamageTestData    {        public static IEnumerable
TestData { get { string[] csvLines = File.ReadAllLines("TestData.csv"); var testCases = new List
(); foreach (var csvLine in csvLines) { IEnumerable
values = csvLine.Split(',').Select(int.Parse); object[] testCase = values.Cast
().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
GetData(MethodInfo testMethod) { yield return new object[] { 0, 100 }; yield return new object[] { 1, 99 }; yield return new object[] { 50, 50 }; yield return new object[] { 101, 1 }; } }}

这里需要实现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简介就到此为止了, 想要深入了解的话, 还是看官方文档吧. 

下面是我的关于ASP.NET Core Web API相关技术的公众号--草根专栏:

转载地址:http://xlxna.baihongyu.com/

你可能感兴趣的文章
互联网技术部门该如何管理
查看>>
微软2014实习生及秋令营技术类职位在线测试-题目3 : Reduce inversion count
查看>>
WebView兼容问题分析报告
查看>>
主机字节序
查看>>
【TYVJ 1056】能量项链
查看>>
手把手教你开发Windows Phone 8应用程序(序)
查看>>
hzk16在项目中的使用
查看>>
pl/sql编程(九)
查看>>
mvn项目中的pom文件提示Error parsing lifecycle processing instructions解决
查看>>
[转] react-router4 + webpack Code Splitting
查看>>
C# 集合 — Hashtable 线程安全
查看>>
Python 第一天
查看>>
检查素数的正则表达式[转]
查看>>
大话数据结构-树
查看>>
DML数据操作语言之查询(二)
查看>>
软件工程作业项目描述
查看>>
一种关键字搜索---edu.cn
查看>>
VS2005环境下采用makefile编译、使用libjpeg.lib函数库
查看>>
科技前沿---全息手机、全息图像
查看>>
代理模式
查看>>