自动化单元测试的意义

自动化单元测试的意义

出处

作者:许式伟
写于:2005年3月
背景:WPS Office 2005 (开发代号: V6)
原文:why-unit-test.pdf (pdf格式)

目录

  • 自动化单元测试的重要特征
  • 单元测试的项目意义
  • 单元测试对设计的意义
  • cppunit for v6
  • 将测试案例写在dll中

常规测试的缺陷

  • 一般是基于手工的,不具备可回归性。因此测试的效率不高。
  • 由于缺乏效率,往往导致测试仅仅针对典型数据,覆盖面往往也很低。

自动化单元测试的重要特征

  • 自动化、可回归性
  • Quiet
  • 案例的执行安全受控

自动化、可回归性

  • 测试的结果是程序直接检测的,而不是“通过人眼对屏幕上的输出结果的观测”
    • 测试的输入数据和预测结果直接在案例中,除非结果非预期,否则不需要任何输出
    • 因此,并不推荐屏幕输出,或者写可视化的测试单元。
    • 案例的执行不需要人工干预,可随时回放。
    • 因此,我们可以通过大量典型测试数据进行回归,以确保系统的可靠性。
  • 对比:常规测试典型过程
    • 在屏幕上提示输入数据,然后打印结果,通过查看屏幕显示的结果,确认我们的系统是否存在问题。

Quiet

  • 绝对避免在案例执行过程中弹出对话框或者进行其他UI交互。
  • (调试模式下例外)

案例的执行安全受控

  • 某个测试案例执行的失败(甚至出现了异常),不会导致测试环境的崩溃,也不影响另一个案例的执行结果。

常规测试样例

void main()
{
int n;
for (;;)
{
std::cout << "input n(0 to exit): ";
std::cin >> n;
if (n== 0)
break;
std::cout << "n! = " << fact(n) << std::endl;
}
}

cppunit测试案例

class TestFact : public TestCase 
{
public:
CPPUNIT_TEST_SUITE(TestFact);
CPPUNIT_TEST(test);
CPPUNIT_TEST_SUITE_END();

void test()
{
CPPUNIT_ASSERT(fact(3) == 6);
CPPUNIT_ASSERT(fact(4) == 24);
CPPUNIT_ASSERT(fact(5) == 120);
}
};

CPPUNIT_TEST_SUITE_REGISTRATION(TestFact);

单元测试的项目意义

  • 模块更加可控。
  • 及早发现问题,提高模块质量,降低系统测试成本。
  • 加速开发周期。

单元测试与项目控制

  • 单元测试不应该是程序员的个人行为,而与项目进度控制、质量控制息息相关。
    • 通过监测单元测试的情况,来量化模块开发的进度与质量。
  • 要改善项目的控制,必须“做好单元测试”。
    • 不止是要让单元测试成为每个程序员的例行公事,而且要让它变得规范、变得受控。

单元测试的误区

  • 一个很常见误解是:嗯,单元测试,好事啊,只是最近时间很紧,下回做吧。
  • 实际上单元测试大家都会去做,我们提倡单元测试,更大程度上是要达到:
    • 规范单元测试的编写(手段);
    • 最大程度保留下来我们的测试案例;

加速开发周期

  • 一个系统自动化程度越高,则运营成本越低。
    • 单元(模块)是最容易,也是最应该采用自动化测试的。而集成测试、系统测试虽然也有自动化的方法和支持工具,但需要更高额的代价。
  • 单元测试将问题的发现周期缩短,降低bug修复成本。
    • 如果问题在集成测试、系统测试期被发现,那么同样一个问题需要花几倍甚至几十倍的时间进行定位、修复。
  • 单元测试降低了集成测试、系统测试的压力和投入成本。

单元测试的主要检查点

  • 案例的覆盖度
  • Bug量与Bug反复情况
  • 案例文档的规范

单元测试对设计的意义

  • 设计应该以可测试性为第一目标。
  • 及时发现模块构架调整引发的潜在Bug。

模块的可测试性

  • 可测试性 = 低耦合
    • 环境模拟(依赖的模块、数据输入)
    • 模块设计应该首先保证可测试性。
    • 坚持进行单元测试可提高设计能力。
  • 一个模块可以很方便地进行测试,那么就可以说它是一个设计优良的模块。

发现模块构架调整的潜在Bug

  • 通常模块在架构调整期(代码重构)最容易引入Bug。
  • 只有在模块开发中就不断积累经典数据、以案例的形式固化已知Bug,才可能在架构调整等最容易引发问题的情形下获得最佳效果。

cppunit for v6

  • 引入调试模式
  • 通用的调试开关
  • 有选择的运行测试案例
  • 独特的dll测试模式

调试模式

  • 同一套测试代码,两种工作模式。
    • cppunit提供了安全可控的自动化测试平台。
    • 但是是代码总会有bug。为了让测试案例可调试,v6在开源的cppunit基础上,结合kfc的调试策略,引入调试模式。

通用的调试开关

  • /ndebug
    • 进入自动化测试模式。默认为调试模式。
  • /output:<xmlfile>
    • 输出结果到xml文件。注意:/output:后不能有空格。
    • 默认输出到控制台。
  • /run:<testclass>[.<testmethod>]
    • 执行<testclass>类所有案例,或者执行<testclass>的<testmethod>案例。

有选择的运行测试案例

  • 你可以只执行某个TestCase类,或者只是执行某个TestCase中的某个method。
  • 演示rununit程序的参数含义:

<testclass> <testmethod>

  • 演示通用开关:

/run:<testclass>[.<testmethod>]

将测试案例写在dll中

  • 测试案例同步更新
  • 测试dll内部组件
  • 关于rununit工具

基于dll的单元测试

  • 对比
    • 为dll写测试程序(exe方式)
  • 优点
    • 方便测试案例的同步更新
      • 并且强迫你同步更新测试案例
    • 可测试dll的内部组件
    • 去除了建立新工程的过程(有点麻烦)。

关于rununit工具

  • 用rununit调试你的dll
    • rununit程序是一个通用的testcaseRunner,可用于执行(或调试)一个dll中的部分或全部案例。
  • 命令行

rununit testcase[.dll] [testclass] [testmethod] [/ndebug] [/pause] [/output:<xmlfile>]

Visual Studio中调试dll

今天,你“单元测试”了吗?

  • 如果你没有,那么我告诉你,你已经落伍啦!

附录

  • rununit.exe: 参考ksdn中关于该程序的详细说明。
  • CreateCppUnitTestCase宏: 参考KSRule.dsm(macros for Visual Studio)。
 

你可能感兴趣的:(自动化单元测试的意义)