通常的单元测试框架都以他们支持的语言的开头字母加上Unit作为名字,他们统称为xUnit框架。C++的叫做CppUnit,Java的叫做JUnit,.Net的叫做NUnit。当然不是所有的都这么命名,但大部分如此。下面我主要讲解一下NUni的一些基本操作。
1:Nunit两个重要属性
1.1:[TestFixture]
这个是标识包含自动化测试的类,可能改成TestClass大家更加理解。但是代码是无法编译过去的。
1.2:[Test]
这个是标识这个方法需要自动化测试的。记得把这个属性加在要测试的方法上。
2:编写第一个单元测试
2.1:一个单元测试通常包含三个行为:
2.1.1:准备对象(就是对哪个对象就行操作)
2.1.2:操作对象(对对象进行一些逻辑处理)
2.1.3:断言(Assert)和预判产生的结果对比
2.2:编写一个判断后缀名的方法
public bool IsValidExtensions(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException("fileName"); var extension = Path.GetExtension(fileName); if (extension.Contains("pdf")) { return true; } return false; }
2.3:编写测试方法
2.3.1:Assert这个类
Assert.IsFalse(bool condition, string message)
参数1:返回的结果 参数2:展示失败的信息
Assert.AreEqual(int expected, int actual, string message)
参数1:期望的结果 参数2:实际的结果 参数3:展示失败的信息
当然Assert很多方法可以自己去学习。
[Test] public void IsValidExtensions_BadExtension_ReturnsFalse() { var arithmetic=new Arithmetic(); bool restlt = arithmetic.IsValidExtensions("log.pdf"); Assert.IsFalse(restlt,"没有返回正确值"); }
2.3.2:编译项目然后打开Nunit,点击NUnit的File打开这个编译的dll文件然后如下图
2.3.3:我们要修改单元测试方法
右键点击上图的ArithmeticTest选择LoadFixture就会重新导入这个ArithmeticTest。ClearFixTure清理这个ArithmeticTest
2.4:使用参数重构测试
比喻上面我们的参数叫做log.pdf但是现在又要测试log.txt怎么办,如果说2个可以写,10个乃至100个呢不用担心NUnit给我们提供了两个特性
[TestCase]
ok我们来修改上面的单元测试代码
[TestCase("log.pdf")] [TestCase("log.txt")] public void IsValidExtensions_BadExtension_ReturnsFalse(string fileName) { var arithmetic=new Arithmetic(); bool restlt = arithmetic.IsValidExtensions(fileName); Assert.IsFalse(restlt,"没有返回正确值"); }
我们在运行NUnit看看效果:
看到效果了吧我们就出现了两个方法。这样一来是不是很简单。
但是有的又说我可不可以指定我预期的效果呢,很明显是可以的我们在此修改测试方法
[TestCase("log.pdf",true)] [TestCase("log.txt",false)] public void IsValidExtensions_BadExtension_ReturnsFalse(string fileName) { var arithmetic=new Arithmetic(); bool restlt = arithmetic.IsValidExtensions(fileName); Assert.IsTrue(restlt,"没有返回预期的值"); }
我们运行会发现这2个都能通过编译这里就不贴图了。
2.5:setup和teardown
setup特性以后表示每次运行这个测试类首先就会进入这个方法相当于我们常说的构造函数
teardown表示方法运行结束以后再运行这个方法,我们常说的析构函数。
如
[setup]A()
[test]B()
[teardown]C()
运行顺序是A到B到C
2.6:异常检测
2.6.1:ExpectedException标识这种标识是很常见的一种测试异常的方法下面来看它的用法
public bool IsValidExtensions(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException(); var extension = Path.GetExtension(fileName); if (extension.Contains("pdf")) { return true; } return false; }[Test] [ExpectedException(typeof(ArgumentNullException),ExpectedMessage = "值不能为 null。")] public void IsVaildFileName_EmptyFileName_ThrowException() { var arithmetic = new Arithmetic(); arithmetic.IsValidExtensions(""); }
第一个参数:表示显示异常的类
第二个参数:表示期望的异常
注意:这个异常并没有调用Assert因为ExpectedException本身带有判断。
我们看看测试结果:
表示异常和我们期待的一样,但是这有一个问题如果我们构造函数抛出一个异常测试同样会通过,所以就会导致测试出现了不真实性。(我测试过在构造函数抛出空异常同样测试通过)
那么就引进了另一个异常的测试方式Lambda表达式来改造一下
[Test] public void IsVaildFileName_EmptyFileName_ThrowException() { var arithmetic = new Arithmetic(); var ex = Assert.Catch<Exception>(() => arithmetic.IsValidExtensions(string.Empty)); StringAssert.Contains("值不能为 null。", ex.Message);//可以不写值不能为Null也能通过测试 }
这样就避免了上面的情况,只要是lambda表达式抛出异常就通过测试否则任何地方抛出异常都不能通过测试。
2.7:忽略测试
有时候有些代码不需要测试,但是你又把它迁入主项目那么你就可以考虑把他忽略掉(当然这种情况很少的)
[Test] [Ignore("这个方法目前不用进行测试")] public void IsVaildFileName_BadExtension_ReturnFalse() { var arithmetic = new Arithmetic(); Assert.IsTrue(arithmetic.IsValidExtensions("11")); }
测试效果:
黄色的就表示暂时不考虑测试的方法。
2.8:设置测试类别
在实际开发中可能我们很多测试,为了分开测试我们可以设置类别,也可以在测试中选择一些分类测试下面我们看看怎么实现的
[Test] [Category("后台单元测试")] public void IsVaildFileName_BadExtension_ReturnFalse() { var arithmetic = new Arithmetic(); Assert.IsTrue(arithmetic.IsValidExtensions("11")); } [Test] [Category("前端单元测试")] public void IsVaildFileName_EmptyFileName_ThrowException() { var arithmetic = new Arithmetic(); var ex = Assert.Catch<Exception>(() => arithmetic.IsValidExtensions(string.Empty)); StringAssert.Contains("值不能为 null。", ex.Message); }
我们看看效果:
大家可以自己动手测试下,实际功能比这强大很多的。
2.9:测试类中某个属性没有返回值怎么办
这个比较简单我直接贴代码了。
public bool IsOnline { get; set; } public void IsValidExtensions(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException(); var extension = Path.GetExtension(fileName); if (!extension.Contains("pdf")) return; IsOnline = true; }
[Test] public void IsVaildFileName_BadExtension_ReturnFalse() { var arithmetic = new Arithmetic(); arithmetic.IsValidExtensions("log.pdf"); Assert.IsTrue(arithmetic.IsOnline); }
这个效果很明显是通过的。这样来验证类的一个属性(但是有一个依耐项)
以上参考单元测试的艺术
- 1楼David111
- 写完单元测试还要把dll加载到窗口中,是否很麻烦呢,我们目前是用Resharper,能够直接在代码中运行单元测试。
- Re: lpnet
- @David111,我也是在用Resharper,不过比较喜欢这种全部通过的蓝条。