zoukankan      html  css  js  c++  java
  • 解读sample1

    说明

    被测试代码文件 sample1.h、sample1.cc
    测试代码文件 sample1_unittest.cc

    官网上如是描述sample1:

    Sample #1 shows the basic steps of using Google Test to test C++ functions.

    sample1演示了如何使用gtest来对C++函数进行单元测试。

    如何把sample1的代码跑起来,请参考我写的另外一篇文章《用Visual Studio创建集成了gtest的命令行工程》(链接:http://www.cnblogs.com/duxiuxing/p/4272343.html)。

    理解被测试代码

    被测试代码是两个全局函数:

    函数名 函数功能
    Factorial() 阶乘运算函数
    IsPrime() 判断入参是否为质数

    理解测试代码:TEST宏

    sample1使用了gtest的TEST宏来组织它的测试代码,TEST宏它有两个参数:

    • 参数1:test_case_name,对应于被测试的函数,比如“FactorialTest”对应的被测试函数是“Factorial”;
    • 参数2:test_name,对应于一组可以独立运行的测试代码。

    这似乎跟我以往对单元测试的认知有所出入,我以前的理解是:

    • 测试用例(Test Case)是最小的执行单位;
    • 一个或几个测试用例组成一个测试包(Test Suite)。

    老牌单元测试框架CppUnit里面也是按照Test Suite和Test Case的概念来组织测试代码的。其实,“gtest的TestCase和Test”and“CppUnit的TestSuite和TestCase”,本质上是一回事,它们只是两套框架内对于相同事物的不同称谓而已。实际上不管你习惯于哪套称谓,在阅读文档的时候有疑问的话,结合上下文,应该也是很容易理解的。

    CoderZh的大作《玩转Google开源C++单元测试框架Google Test系列(gtest)之一 - 初识gtest》(链接:http://www.cnblogs.com/coderzh/archive/2009/03/31/1426758.html)中提到:

    我们使用了TEST这个宏,它有两个参数,官方的对这两个参数的解释为:[TestCaseName,TestName],而我对这两个参数的定义是:[TestSuiteName,TestCaseName]。

    在进行单元测试的时候,我们可以用若干组测试代码,从不同的维度来测试同一个函数,test_case_name和test_name是一对多的关系。这种组织关系从sample1的执行结果很容易看出来:

    第1组test case的代码是这么组织的:

    被测试的函数 Factorial()
    test case name FactorialTest
      - test name 1 Negative:测试入参<0的情况
      - test name 2 Zero:测试入参=0的情况
      - test name 3 Positive:测试入参>0的情况

    第2组test case的代码是这么组织的:

    被测试的函数 IsPrime()
    test case name IsPrimeTest
      - test name 1 Negative:测试入参<0的情况
      - test name 2 Trivial:测几个特殊的入参
      - test name 3 Positive:测试入参>0的情况

    理解测试代码:EXPECT_*断言和ASSERT_*断言

    对于sample1的两个被测试函数来说,单元测试要做的事情就是:

    1. 设定输入;
    2. 执行被测试函数;
    3. 判断输出是否符合预期。

    在“判断输出是否符合预期”这一步,代码中使用了EXPECT_*宏,我们把这类宏称为断言。当一个EXPECT_*断言检查到不符合预期的情况时(简称为“断言失败”),gtest会在屏幕上输出该断言的位置(源文件路径和代码行号)和错误信息。

    与EXPECT_*断言一一对应的还有ASSERT_*断言,它们的区别在于:

    • ASSERT_*断言失败时会产生致命失败,并结束当前函数(简单理解就是会调用return)。
    • EXPECT_*断言产生非致命失败,代码会继续往下执行,而不会终止当前函数。

    两者的使用场景小结:

    • 通常更推荐使用EXPECT_*断言,因为在同一个测试函数中,可能存在多处断言失败的情况,使用EXPECT_*断言能够发现一次运行中的所有失败情况。
    • 当某个断言失败就没有必要继续往下执行的时候,应该使用ASSERT_*断言。
    • ASSERT_*断言失败会立刻从当前的代码返回,这可能导致当前代码之后的一些“清洁回收”代码没有被执行,进而出现内存泄漏。这种问题一旦发现,是应该通过调整测试代码来修复的。

    理解测试代码:检查数值比较结果的断言

    Factorial()是一个阶乘运算函数,它的原型如下:

    // Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
    int Factorial(int n);

    对Factorial()进行单元测试的时候,sample1_unittest.cc中使用了一组检查数值比较结果的断言:     

    致命断言(Fatal assertion) 非致命断言(Nonfatal assertion) 预期结果(Verifies)
    ASSERT_EQ(expected, actual); EXPECT_EQ(expected, actual); expected == actual
    ASSERT_NE(val1, val2); EXPECT_NE(val1, val2); val1 != val2
    ASSERT_LT(val1, val2); EXPECT_LT(val1, val2); val1 < val2
    ASSERT_LE(val1, val2); EXPECT_LE(val1, val2); val1 <= val2
    ASSERT_GT(val1, val2); EXPECT_GT(val1, val2); val1 > val2
    ASSERT_GE(val1, val2); EXPECT_GE(val1, val2); val1 >= val2

    理解测试代码:检查布尔值的断言

    IsPrime()用于判断入参是否为质数 ,它的原型如下:

    // Returns true iff n is a prime number.
    bool IsPrime(int n);

    对IsPrime()进行单元测试的时候,sample1_unittest.cc使用了一组检查布尔值的断言:

    致命断言(Fatal assertion) 非致命断言(Nonfatal assertion) 预期结果(Verifies)
    ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
    ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false

    系列文章索引:http://www.cnblogs.com/duxiuxing/p/4270836.html

  • 相关阅读:
    pythos.access()
    CSS简笔画:纯CSS绘制一艘邮轮
    【每日坚果】如何成为一名数据工匠?
    【博客园使用小指南】DIY美化博客园小指南--主题设置
    乐字节Java反射之一:反射概念与获取反射源头Class
    乐字节Java面向对象三大特性以及Java多态
    在乐字节学习的一天(持续跟新……)
    在乐字节学习的一天(持续跟新……)
    乐字节Java变量与数据类型之二:Java常量与变量
    乐字节Java变量与数据类型之一:Java编程规范,关键字与标识符
  • 原文地址:https://www.cnblogs.com/duxiuxing/p/4289989.html
Copyright © 2011-2022 走看看