Gtest:断言

一、前言

这篇文章主要参考 玩转Google开源C++单元测试框架Google Test系列(gtest)之二 - 断言 ,结合自己平时使用的Linux环境适当删减修改。

Assertion引发的三种结果

Assertions会引发3种结果:success、Non-Fatal Failure、Fatal Failure

Non-Fatal Failure 和 Fatal Failure啥区别?

前者失败后还会继续执行,后者失败后停止执行。ASSERT_* 系列的断言属于fatal assertion,EXPECT_* 系列的断言属于nonfatal assertion。

二、示例
#include <cstdio>
#include <gtest/gtest.h>

int Add(const int& a, const int& b) {
  return a + b;
}

namespace {
  TEST(AddTest, test_001) {
	EXPECT_EQ(4, Add(1 , 2));
  }
}

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

假如你的Add(1, 2) 结果为4的话,会在结果中输出:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from AddTest
[ RUN ] AddTest.test_001
/root/projects/Gtest_assertion/main.cpp:10: Failure
Expected equality of these values:
4
Add(1 , 2)
Which is: 3
[ FAILED ] AddTest.test_001 (0 ms)
[----------] 1 test from AddTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] AddTest.test_001

1 FAILED TEST
View Code

如果是将结果输出到xml里的话,将输出:(关于将结果输出为xml,见:http://www.cnblogs.com/coderzh/archive/2009/04/10/1432789.html

由于我使用的环境是VS2017远程连接Linux开发,所有代码最终还是在Linux上面,VS里面没有办法指定--gtest_output,我只能在Linux上面手动指定

Gtest_assertion.out --gtest_output="xml:report.xml"
[root@1708 Debug]# cat report.xml 
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="1" failures="1" disabled="0" errors="0" timestamp="2019-01-05T19:36:28" time="0.001" name="AllTests">
  <testsuite name="AddTest" tests="1" failures="1" disabled="0" errors="0" time="0.001">
    <testcase name="test_001" status="run" time="0.001" classname="AddTest">
      <failure message="/root/projects/Gtest_assertion/main.cpp:10
Expected equality of these values:
  4
  Add(1 , 2)
    Which is: 3" type=""><![CDATA[/root/projects/Gtest_assertion/main.cpp:10
Expected equality of these values:
  4
  Add(1 , 2)
    Which is: 3]]></failure>
    </testcase>
  </testsuite>
</testsuites>
View Code

如果你对自动输出的出错信息不满意的话,你还可以通过操作符<<将一些自定义的信息输出,通常,这对于调试或是对一些检查点的补充说明来说,非常有用!

改进上面代码

#include <cstdio>
#include <gtest/gtest.h>

int Add(const int& a, const int& b) {
    return a + b;
}

namespace {
    TEST(AddTest, test_001) {
        EXPECT_EQ(4, Add(1 , 2)) << "Add(1 , 2)= " << Add(1, 2);
    }
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
View Code

使用<<操作符将一些重要信息输出的话:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from AddTest
[ RUN      ] AddTest.test_001
/root/projects/Gtest_assertion/main.cpp:10: Failure
Expected equality of these values:
  4
  Add(1 , 2)
    Which is: 3
Add(1 , 2)= 3
[  FAILED  ] AddTest.test_001 (0 ms)
[----------] 1 test from AddTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] AddTest.test_001

 1 FAILED TEST
View Code
三、布尔值检查
Fatal assertionNonfatal assertionVerifies
ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition is true
ASSERT_FALSE(condition);EXPECT_FALSE(condition);condition is false

四、数值型数据检查

Fatal assertionNonfatal assertionVerifies
ASSERT_EQ(expectedactual);EXPECT_EQ(expectedactual);expected == actual
ASSERT_NE(val1val2);EXPECT_NE(val1val2);val1 != val2
ASSERT_LT(val1val2);EXPECT_LT(val1val2);val1 < val2
ASSERT_LE(val1val2);EXPECT_LE(val1val2);val1 <= val2
ASSERT_GT(val1val2);EXPECT_GT(val1val2);val1 > val2
ASSERT_GE(val1val2);EXPECT_GE(val1val2);val1 >= val2

五、字符串检查 

Fatal assertionNonfatal assertionVerifies
ASSERT_STREQ(expected_stractual_str);EXPECT_STREQ(expected_stractual_str);the two C strings have the same content
ASSERT_STRNE(str1str2);EXPECT_STRNE(str1str2);the two C strings have different content
ASSERT_STRCASEEQ(expected_stractual_str);EXPECT_STRCASEEQ(expected_stractual_str);the two C strings have the same content, ignoring case
ASSERT_STRCASENE(str1str2);EXPECT_STRCASENE(str1str2);the two C strings have different content, ignoring case


*STREQ*和*STRNE*同时支持char*和wchar_t*类型的,*STRCASEEQ*和*STRCASENE*却只接收char*,估计是不常用吧。下面是几个例子:

TEST(StringCmpTest, Demo)
{
    char* pszCoderZh = "CoderZh";
    wchar_t* wszCoderZh = L"CoderZh";
    std::string strCoderZh = "CoderZh";
    std::wstring wstrCoderZh = L"CoderZh";

    EXPECT_STREQ("CoderZh", pszCoderZh);
    EXPECT_STREQ(L"CoderZh", wszCoderZh);

    EXPECT_STRNE("CnBlogs", pszCoderZh);
    EXPECT_STRNE(L"CnBlogs", wszCoderZh);

    EXPECT_STRCASEEQ("coderzh", pszCoderZh);
    //EXPECT_STRCASEEQ(L"coderzh", wszCoderZh);    不支持

    EXPECT_STREQ("CoderZh", strCoderZh.c_str());
    EXPECT_STREQ(L"CoderZh", wstrCoderZh.c_str());
}
View Code

 六、显示返回成功或失败

这些断言实际上不测试值或表达式。 相反,它们直接产生成功或失败。 与实际执行测试的宏类似,您可以将自定义失败消息流入它们。

SUCCEED();

直接返回成功:

生成成功。 这不会使整体测试成功。 只有当测试在其执行期间没有任何断言失败时,测试才被认为是成功的。

注意:SUCCEED() is purely documentary,目前不生成任何用户可见的输出。 但是,我们可能会在未来向Google Test的输出中添加SUCCEED()消息

Fatal assertionNonfatal assertionNonfatal assertion
FAIL();ADD_FAILURE();ADD_FAILURE_AT("file_path",line_number);

FAIL()产生致命故障,而ADD_FAILURE()和ADD_FAILURE_AT()产生非致命故障。

如果用于控制流程而不是单纯判断boolean expression,这3个宏会很有用。代码如下

TEST(ExplicitTest, Demo)
{
    ADD_FAILURE() << "Sorry"; // None Fatal Asserton,继续往下执行。

    //FAIL(); // Fatal Assertion,不往下执行该案例。

    SUCCEED();
}
View Code

注意:你只能在返回void的函数中使用FAIL()。 有关详细信息,请参阅 Assertion Placement section 部分。

七、异常断言
Fatal assertionNonfatal assertionVerifies
ASSERT_THROW(statementexception_type);EXPECT_THROW(statementexception_type);statement throws an exception of the given type
ASSERT_ANY_THROW(statement);EXPECT_ANY_THROW(statement);statement throws an exception of any type
ASSERT_NO_THROW(statement);EXPECT_NO_THROW(statement);statement doesn't throw any exception

例如:

int Foo(int a, int b)
{
    if (a == 0 || b == 0)
    {
        throw "don't do that";
    }
    int c = a % b;
    if (c == 0)
        return b;
    return Foo(b, c);
}

TEST(FooTest, HandleZeroInput)
{
    EXPECT_ANY_THROW(Foo(10, 0));
    EXPECT_THROW(Foo(0, 5), char*);
}
View Code
八、Predicate Assertions for Better Error Messages

尽管Google Test拥有丰富的断言,但它们永远不会完整,因为预测用户可能遇到的所有场景是不可能的(也不是一个好主意)。因此,有时用户必须使用EXPECT_TRUE()来检查复杂表达式,因为缺少更好的宏。这样做有个问题,EXPECT_TRUE()没有显示表达式部分的值,这使你很难理解出错的地方。作为一种解决方法,一些用户选择自己构造失败消息,将其流式传输到EXPECT_TRUE()。但是当表达式有副作用(side-effects)又或者计算费时 ,可能会导致某些奇怪问题。

Gtest提供了3种不同方式解决这个问题。

使用现有的布尔函数

如果你已经有一个function或functor返回bool(或一个可以隐式转换为bool的类型),你可以在谓词断言(predicate assertion)中不受任何限制的打印出函数参数。

Fatal assertionNonfatal assertionVerifies
ASSERT_PRED1(pred1, val1);EXPECT_PRED1(pred1, val1);pred1(val1) returns true
ASSERT_PRED2(pred2, val1, val2);EXPECT_PRED2(pred2, val1, val2);pred2(val1, val2) returns true
.........

在上面,predn是一个n元predicate function 或 functor,,其中val1,val2,...和valn是它的参数。 如果谓词(predicate )在应用于给定参数时返回true,则断言成功,否则失败。 当断言失败时,它打印每个参数的值。 在任何一种情况下,参数只计算一次。

Here's an example:

//如果m和n没有除1之外的公约数,则返回true。
bool MutuallyPrime(int m, int n) { ... }
const int a = 3;
const int b = 4;
const int c = 10;

  断言EXPECT_PRED2(Mutual Prime,a,b); 将成功,而断言EXPECT_PRED2(MutuallyPrime,b,c); 将失败。

!MutuallyPrime(b, c) is false, where
b is 4
c is 10

注意:

 1. 如果在使用ASSERT_PRED *或EXPECT_PRED *时看到编译器错误“no matching function to call(无匹配函数调用)”,请参阅此常见问题解答 this FAQ 以了解如何解决它。
 2. 目前我们只提供 <= 5个参数的的predicate assertions。

使用返回AssertionResult的函数

虽然EXPECT_PRED*() and friends对快速工作很方便,但是语法不令人满意:应对不同情况你必须使用不同的宏,它感觉更像Lisp而不是C ++。 :: testing :: AssertionResult类解决了这个问题。

AssertionResult对象表示断言的结果(无论它是成功还是失败,以及相关联的消息)。 您可以使用以下工厂函数之一创建AssertionResult:

namespace testing {

// Returns an AssertionResult object to indicate that an assertion has
// succeeded.
AssertionResult AssertionSuccess();

// Returns an AssertionResult object to indicate that an assertion has
// failed.
AssertionResult AssertionFailure();

}

  你可以使用<<运算符将消息流式传输到AssertionResult对象。

要在布尔断言(例如EXPECT_TRUE())中提供更多可读消息,请编写一个返回AssertionResult而不是bool的谓词函数。 例如,如果您将IsEven()定义为:

::testing::AssertionResult IsEven(int n) {
  if ((n % 2) == 0)
    return ::testing::AssertionSuccess();
  else
    return ::testing::AssertionFailure() << n << " is odd";
}

  而不是

bool IsEven(int n) {
  return (n % 2) == 0;
}

  针对EXPECT_TRUE(IsEven(Fib(4)))错误的断言将要输出

Value of: IsEven(Fib(4))
Actual: false (*3 is odd*)
Expected: true 

而不是这种特别模糊的输出

Value of: IsEven(Fib(4))
Actual: false
Expected: true

  如果想要在EXPECT_FALSE and ASSERT_FALSE中也输出大量有用信息们可以这样做

::testing::AssertionResult IsEven(int n) {
  if ((n % 2) == 0)
    return ::testing::AssertionSuccess() << n << " is even";
  else
    return ::testing::AssertionFailure() << n << " is odd";
}

  EXPECT_FALSE(IsEven(Fib(6)))将会打印输出

Value of: IsEven(Fib(6))
Actual: true (8 is even)
Expected: false

  使用谓词格式化(Predicate-Formatter)

如果你发现由(ASSERT | EXPECT)_PRED *和(ASSERT | EXPECT)_(TRUE | FALSE)生成的默认消息不令人满意,或者您的predicate的某些参数不支持流到ostream,您可以使用以下predicate-formatter assertions来完全定义消息的格式:

Fatal assertionNonfatal assertionVerifies
ASSERT_PRED_FORMAT1(pred_format1, val1);EXPECT_PRED_FORMAT1(pred_format1, val1);pred_format1(val1) is successful
ASSERT_PRED_FORMAT2(pred_format2, val1, val2);EXPECT_PRED_FORMAT2(pred_format2, val1, val2);pred_format2(val1, val2) is successful
.........

这和(ASSERT | EXPECT)_PRED *宏的区别是,这一节讲的宏不是一个谓词,(ASSERT | EXPECT)_PRED_FORMAT *接收一个predicate-formatter(pred_formatn),它是一个函数或函数签名

::testing::AssertionResult PredicateFormattern(const char*expr1, const char*expr2, ... const char*exprn, T1 val1, T2 val2, ... Tn valn);

val1, val2, ..., 和valn 是predicate arguments的值。expr1, expr2, ..., 和 exprn是出现在代码中相应的表达式。T1, T2, ..., 和Tn可以试值类型,也可以是引用类型。举例来说,如果一个参数的类型是Foo,你把T*设置成Foo或const Foo&都可以。

predicate-formatter返回一个::testing::AssertionResult对象用于指明断言(assertion)成功与否,创建::testing::AssertionResult对象的唯一方式是使用下列工厂函数(factory functions)

一个例子,改善之前使用EXPECT_PRED2()那个例子的错误信息

// Returns the smallest prime common divisor of m and n,
// or 1 when m and n are mutually prime.
int SmallestPrimeCommonDivisor(int m, int n) { ... }

// A predicate-formatter for asserting that two integers are mutually prime.
::testing::AssertionResult AssertMutuallyPrime(const char* m_expr,
                                               const char* n_expr,
                                               int m,
                                               int n) {
  if (MutuallyPrime(m, n))
    return ::testing::AssertionSuccess();

  return ::testing::AssertionFailure()
      << m_expr << " and " << n_expr << " (" << m << " and " << n
      << ") are not mutually prime, " << "as they have a common divisor "
      << SmallestPrimeCommonDivisor(m, n);
}

  借助predicate-formatter,我们可以使用

EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c);

  会生成消息

b and c (4 and 10) are not mutually prime, as they have a common divisor 2.

  事实上前面引入的许多断言都是(EXPECT|ASSERT)_PRED_FORMAT*的特例,他们中大多数也是使用(EXPECT|ASSERT)_PRED_FORMAT*.定义的。

九、浮点型检查

比较浮点数是棘手的。 由于舍入误差,两个浮点不太可能完全匹配。 因此,ASSERT_EQ的较傻的比较通常不起作用。 并且由于浮点可以具有宽的值范围,没有单个固定误差界限工作。 最好通过固定的相对误差界限进行比较,除了接近0的值由于精度的损失。

一般来说,对于浮点比较有意义,用户需要仔细选择误差界限。 如果他们不想要或关心,根据最后地点(ULP)中的单位进行比较是一个很好的默认值,Google测试提供了断言来做到这一点。 关于ULP的完整详细信息相当长; 如果你想了解更多,请参阅这篇关于浮动比较的文章 this article on float comparison.。

Fatal assertionNonfatal assertionVerifies
ASSERT_FLOAT_EQ(expected, actual);EXPECT_FLOAT_EQ(expected, actual);the two float values are almost equal
ASSERT_DOUBLE_EQ(expected, actual);EXPECT_DOUBLE_EQ(expected, actual);the two double values are almost equal

对相近的两个数比较:

Fatal assertionNonfatal assertionVerifies
ASSERT_NEAR(val1, val2, abs_error);EXPECT_NEAR(val1, val2, abs_error);the difference between val1 and val2 doesn't exceed the given absolute error

 同时,还可以使用:

EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2);
EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);
十、Windows HRESULT assertions
Fatal assertionNonfatal assertionVerifies
ASSERT_HRESULT_SUCCEEDED(expression);EXPECT_HRESULT_SUCCEEDED(expression);expression is a success HRESULT
ASSERT_HRESULT_FAILED(expression);EXPECT_HRESULT_FAILED(expression);expression is a failure HRESULT

例如:

CComPtr shell;
ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application"));
CComVariant empty;
ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty));
十一、类型断言

可以调用函数

::testing::StaticAssertTypeEq<T1, T2>();

来声称断言类型T1和T2是相同的。 如果满足断言,该函数不执行任何操作。 如果类型不同,函数调用将无法编译,编译器错误消息(取决于编译器)将显示T1和T2的实际值。 这主要在模板代码中有用。

注意:当在类模板或函数模板的成员函数中使用时,StaticAssertTypeEq <T1,T2>()仅在函数实例化时有效。 例如,给定:

template <typename T> class Foo {
 public:
  void Bar() { ::testing::StaticAssertTypeEq<int, T>(); }
};

     the code:

void Test1() { Foo<bool> foo; }

  将不会生成编译器错误,因为Foo <bool> :: Bar()永远不会实际实例化。 相反,您需要:

void Test2() { Foo<bool> foo; foo.Bar(); }

  导致编译器错误。

暂时用到的就这些,剩下的参考:

Gtest AdvancedGuide 对于国内译文 Google C++单元测试框架GoogleTest---AdvancedGuide(译文)上 (疑问有多处翻译bug,看的时候别全信)

其他文章:

C++单元测试框架Googletest

单元测试工具gtest使用笔记

专题:

GoogleTest单元测试

单元测试

转载于:https://www.cnblogs.com/kelamoyujuzhen/p/10223860.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值