单元测试 学习笔记 之三
第三章 单元测试的工具——测试框架
3.1 常用的单元测试框架
工欲善其事, 必先利其器. 程序员在写单元测试代码时, 如果能借助一些单元测试框架, 那么使单元测试代码的书写、维护、分类、存档、运行和结果检查变得更为容易, 从而成倍地提高工作效率. 在本章中, 我们就将学习两种单元测试的框架.
第一种, 就是鼎鼎大名的xUnit测试框架家族. xUnit测试框架有助于我们更加结构化地书写测试代码, 更方便地运行单元测试并检查运行结果.
第二种框架称为隔离框架(isolation framework). 这种框架旨在帮助程序员自动地生成FakeCollaboratorClass代码. 但是隔离框架一般都要求ClassUnderTest依赖于CollaboratorService抽象接口, 而不是具体类CollaboratorClass, 所以在使用"Virtual and Override"手法时, 隔离框架就帮不忙了, 必须由程序员手写FakeCollaboratorClass的代码.
在接下来的几个小节中, 我们将针对C++, C#和Java语言, 分别介绍适用于它们的单元测试框架.
3.2 用于C++的单元测试框架
对于C++, 我们推荐使用Google C++ Unit Testing Framework(简称gTest, 目前为1.5版)加HippoMocks(目前为3.1版)的组合. 如下的表格演示了如何使用这两个框架.
gTest的基本用法 | |
声明Test Fixture | #ifndef CLASS_UNDER_TEST_TEST_H |
定义Test Method | // In [ClassUnderTest]Test.cpp file. // Temporarily ignore a test case. TEST_F([ClassUnderTest]Test, DISABLE_[Feature]_[Scenario]_[ExpectedBehavior]) |
Test Runner | // Currently, gTest only supports CUI. The main() should be like this. |
gTest支持的命令行参数 | |
--gtest-filter=[filter] | 对执行的测试案例进行过滤,支持 |
--gtest_repeat=[COUNT] | 设置案例重复运行次数. 比如: |
--gtest_print_time | 打印每个测试方法运行的所用时间. |
--gtest_catch_exceptions | 捕捉异常. 这样当测试方法中抛出了异常时, 不会阻碍了后续测试方法的运行. 注意: 这个参数只在Windows下有效. |
--gtest_output=xml[:DIRECTORY_PATH/|:FILE_PATH] | 产生XML格式的报告。 |
gTest支持的断言 | |
断言真伪 | ASSERT_TRUE(condition) [<< message]; |
断言比较关系 | ASSERT_EQ(expected, actual) [<< message]; |
断言C字符串关系 | ASSERT_STREQ(expected_cstr, actual_cstr) [<< message]; |
断言异常 | ASSERT_THROW({ statements }, exception_ctor); |
HippoMocks用于动态stub生成 | |
准备工作 | // In [ClassUnderTest]Test.cpp file. |
指定返回值 | // We don't care about the passed-in arguments for CollaboratorService::methodName(). |
指定抛出异常 | // We don't care about the passed-in arguments for CollaboratorService::methodName(). |
HippoMocks用于动态mock生成 | |
准备工作 | // In [ClassUnderTest]Test.cpp file. |
设置期望: | mockEngine.NeverCall(mock, CollaboratorService::methodName); |
设置期望: | mockEngine.OnCall(mock, CollaboratorService::methodName); |
设置期望: | mockEngine.OnCall(mock, CollaboratorService::methodName).With(arg1, arg2, ...); |
设置期望: | mockEngine.ExpectCall(mock, CollaboratorService::methodName); |
设置期望: | mockEngine.ExpectCall(mock, CollaboratorService::methodName).With(arg1, arg2, ...); |
设置期望: | mockEngine.autoExpect = false; |
设置期望: | mockEngine.ExpectCall(mock, CollaboratorService::methodName1); |
显式验证 | mockEngine.VerifyAll(); |
3.3 用于C#的单元测试框架
对于C#, 我们推荐使用NUnit(目前为2.5版)加RhinoMocks(目前为3.6版)的组合. 如下的表格演示了如何使用这两个框架.
NUnit的基本用法 | |
Test Fixture和Test Method | using NUnit.Framework; // Temporarily ignore a test case. [Test] [Ignore] } |
Test Runner | NUnit提供了GUI界面的Test Runner, 只需把编译生成的程序集(assembly)加载到该Test Runner中即可. |
NUnit支持的断言 | |
断言真伪 | Assert.That(condition, Is.True); |
断言比较关系 | Assert.That(actual, Is[.Not].EqualTo(expected)); |
断言对象关系 | Assert.That(obj, Is[.Not].Null); |
断言容器关系 | Assert.That(container, Is[.Not].Empty); |
断言字符串关系 | Assert.That(actual, Is[.Not].EqualTo(expected)[.IgnoreCase]); |
断言异常 | Assert.That(() => { statements }, Throws.Exception.TypeOf<exception_ctor>()); |
RhinoMocks用于动态stub生成 | |
准备工作 | using NUnit.Framework; |
指定返回值 | // We don't care about the passed-in arguments for CollaboratorService::methodName(). |
指定抛出异常 | // We don't care about the passed-in arguments for CollaboratorService::methodName(). |
RhinoMocks用于动态mock生成 | |
准备工作 | using NUnit.Framework; |
设置期望: | Expect.Call(() => { mock.methodName(dummy1, dummy2, ...); }).Repeat.Never(); |
设置期望: | Expect.Call(() => { mock.methodName(dummy1, dummy2, ...); }).Repeat.Any(); |
设置期望: | Expect.Call(() => { mock.methodName(dummy1, dummy2, ...); }). |
设置期望: | Expect.Call(() => { mock.methodName(arg1, arg2, ...); }); |
设置期望: | Expect.Call(() => { mock.methodName1(arg1, arg2, ...); }); |
设置期望: | using (mockEngine.Ordered()) |
显式验证 | mockEngine.VerifyAll(); |