现在,您已阅读底漆并学会了如何编写使用谷歌测试的测试,它是时间来学习一些新花样。本文档将向您展示更多的说法,并如何构建复杂的故障消息,传播致命故障、 重用和加快您的测试夹具、 以及您的测试使用各种标志。
更多的断言
本部分介绍了一些不太常用,但仍然很大,断言。
显式的成功和失败
这些三断言不实际测试的值或表达式。相反,它们产生的成败直接。像实际执行测试的宏,您可能将他们流自定义失败消息。
生成成功。这不会使整体测试成功。测试被认为没有其主张在执行过程中失败,才成功。
注: SUCCEED() ,是纯粹的纪录片和目前不会生成任何用户可见的输出。不过,我们可能会将SUCCEED()消息在将来添加到 Google 测试输出。
FAIL() ; | ADD_FAILURE() ; | ADD_FAILURE_AT ("file_path", line_number); |
FAIL()生成致命的失败,而ADD_FAILURE()和ADD_FAILURE_AT()生成一个非致命的失败。这些都是很有用的时候控制流,而不是 deteremines 的布尔表达式,测试的成功或失败。例如,您可能要写类似:
switch(expression) {
case 1: ... some checks ...
case 2: ... some other checks
...
default: FAIL() << "We shouldn't get here.";
}
可用性: Linux、 Windows、 mac。
异常的断言
这些是用于验证那一块的代码引发 (或不会引发) 给定类型的异常:
致命的断言 | 非致命的断言 | 验证 |
ASSERT_THROW (语句, exception_type); | EXPECT_THROW (语句, exception_type); | 语句引发给定类型的异常 |
ASSERT_ANY_THROW (语句); | EXPECT_ANY_THROW (语句); | 语句引发的任何类型的异常 |
ASSERT_NO_THROW (语句); | EXPECT_NO_THROW (语句); | 语句不会引发任何异常 |
示例:
ASSERT_THROW(Foo(5), bar_exception);
EXPECT_NO_THROW({
int n = 5;
Bar(&n);
});
可用性: Linux、 Windows、 Mac ;自从 1.1.0 版。
谓词断言有更好的错误消息
尽管谷歌测试有一套丰富的断言,他们不能完成,它是不可能 (也不错) 期待所有方案用户可能会都遇到。因此,有时用户必须使用EXPECT_TRUE()来检查复杂表达式,为更好地宏的缺乏。这有没有显示您的值的表达式,从而很难理解到底哪里错了部分问题。作为一种解决方法,一些用户选择构建失败消息本身,它流到EXPECT_TRUE()。不过,这是尴尬,尤其是当表达式具有副作用或贵评估。
谷歌测试为您提供了三种不同的选择,以解决此问题:
使用现有的布尔函数
如果您已经有一个函数或返回布尔值的函 (或可以隐式转换为bool类型),您可以将它使用谓词断言获得免费打印函数的参数:
致命的断言 | 非致命的断言 | 验证 |
ASSERT_PRED1 (pred1、 val1); | EXPECT_PRED1 (pred1、 val1); | pred1(val1) ,则返回 true |
ASSERT_PRED2 (pred2、 val1、 val2); | EXPECT_PRED2 (pred2、 val1、 val2); | pred2(val1, val2) ,则返回 true |
... | ... | ... |
在以上所述, predn是n-叉谓词函数或函子,凡val1、 val2,… … 和valn都是它的参数。断言成功如果谓语返回true时应用于给定的参数,而另有失败。当断言失败时,它将打印的每个参数的值。在任一情况下,参数计算一次。
下面是一个示例。鉴于
// Returns true iff m and n have no common divisors except 1.
bool MutuallyPrime(int m, int n) { ... }
const int a = 3;
const int b = 4;
const int c = 10;
断言EXPECT_PRED2 (MutuallyPrime,a、 b) ;将会取得成功,同时断言EXPECT_PRED2 (MutuallyPrime,b、 c) ;将会失败,并显示消息
MutuallyPrime(b, c) is false, where
b is 4
c is 10
备注:
- 如果您看到"没有匹配的调用的函数"编译器错误,使用ASSERT_PRED *或EXPECT_PRED *时,请参阅该如何解决这个问题。
- 目前我们只提供 arity 的谓词断言 < = 5。如果您需要更高 arity 断言,让我们知道。
可用性: Linux、 Windows、 Mac
使用一个函数,返回 AssertionResult
EXPECT_PRED*()和朋友虽然方便快速的工作,该语法不令人满意: 你要为不同的矿井,使用不同的宏和感觉更像是比 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 。例如,如果定义为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和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
可用性: Linux、 Windows、 Mac ;自从版本 1.4.1。
使用谓词格式化程序
如果您发现由(ASSERT| 生成的默认消息预计) _PRED *和(ASSERT|预计) _ (TRUE|FALSE)不理想,或您的谓词的一些参数不支持流到ostream,则可以使用以下谓词-格式化程序断言来完全自定义设置消息的格式:
致命的断言 | 非致命的断言 | 验证 |
ASSERT_PRED_FORMAT1 (pred_format1、 val1); | EXPECT_PRED_FORMAT1 (pred_format1、 val1`); | pred_format1(val1)是成功 |
ASSERT_PRED_FORMAT2 (pred_format2、 val1、 val2); | EXPECT_PRED_FORMAT2 (pred_format2、 val1、 val2); | pred_format2(val1, val2)成功 |
... | ... | ... |
这和以前的两个组的宏之间的区别是,而不是一个谓词, (ASSERT|期待) _PRED_FORMAT *采取谓词-格式化程序(pred_formatn),这是函数或函子与签名:
:: testing::AssertionResult PredicateFormattern (const char * expr1、 const char * expr2、 … … const char * exprn、 T1val1、 T2 val2… …Tn valn);
凡val1、 val2,… … 和valn是谓词参数和expr1、 expr2,… … 和exprn的值是相应的表达式,它们出现在源代码中。T1、 T2,… … 和Tn的类型可以是值类型或引用类型。例如,如果参数类型Foo,可以声明为美孚或const 美孚 &,选择适合。
A predicate-formatter returns a ::testing::AssertionResult object to indicate whether the assertion has succeeded or not. The only way to create such an object is to call one of these factory functions:
As an example, let's improve the failure message in the previous example, which uses 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);
}
With this predicate-formatter, we can use
EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c);
to generate the message
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
As you may have realized, many of the assertions we introduced earlier are special cases of (EXPECT|ASSERT)_PRED_FORMAT*. In fact, most of them are indeed defined using (EXPECT|ASSERT)_PRED_FORMAT*.
Availability: Linux, Windows, Mac.
Floating-Point Comparison
Comparing floating-point numbers is tricky. Due to round-off errors, it is very unlikely that two floating-points will match exactly. Therefore,ASSERT_EQ 's naive comparison usually doesn't work. And since floating-points can have a wide value range, no single fixed error bound works. It's better to compare by a fixed relative error bound, except for values close to 0 due to the loss of precision there.
一般情况下,对于进行有意义的浮点比较,用户需要仔细选择绑定错误。如果他们不想要或愿意,单位的角度比较在最后的位置 (ULPs) 是很好的默认情况下,和谷歌测试提供了断言来执行此操作。ULPs 的所有细节都都很长 ;如果您想了解更多信息,请参见本文浮法比较.
浮点宏
致命的断言 | 非致命的断言 | 验证 |
ASSERT_FLOAT_EQ (预期的、 实际); | EXPECT_FLOAT_EQ (预期的、 实际); | 这两个浮点值几乎相等 |
ASSERT_DOUBLE_EQ (预期的、 实际); | EXPECT_DOUBLE_EQ (预期的、 实际); | 两个双精度值几乎相等 |
所谓"几乎相等,"我们是属于 4 辛从对方的两个值。
以下的断言允许您选择绑定的可接受的错误:
致命的断言 | 非致命的断言 | 验证 |
ASSERT_NEAR (val1、 val2、 abs_error); | EXPECT_NEAR(val1,val2,abs_error); | val1和val2之间的区别不超过给定绝对错误 |
可用性: Linux、 Windows、 mac。
浮点谓词格式函数
一些浮点运算是有用的但不是经常使用。为了避免新的宏的爆炸,我们提供作为谓词格式函数,可用于谓词断言宏 (如EXPECT_PRED_FORMAT2等)。
EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2);
EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2);
验证该val1是否小于,或几乎等于val2。您可以使用ASSERT_PRED_FORMAT2上, 表中替换EXPECT_PRED_FORMAT2.
可用性: Linux、 Windows、 mac。
Windows HRESULT 断言
这些断言测试HRESULT成功或失败。
致命的断言 | 非致命的断言 | 验证 |
ASSERT_HRESULT_SUCCEEDED (的表达); | EXPECT_HRESULT_SUCCEEDED (的表达); | 表达式是一个成功的 HRESULT |
ASSERT_HRESULT_FAILED (的表达); | EXPECT_HRESULT_FAILED (的表达); | 表达式是一个失败HRESULT |
生成的输出包含与表达式返回HRESULT代码关联的人类可读的错误消息.
您可以使用它们像这样:
CComPtr shell;
ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application"));
CComVariant empty;
ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty));
可用性: Windows。
类型的断言
你可以调用该函数
::testing::StaticAssertTypeEq<T1, T2>();
断言的T1和T2类型都是相同。如果断言纳则函数没有任何效果。如果类型不同,函数调用将无法编译,以及编译器错误消息可能会 (具体取决于编译器) 显示您的T1和T2实际值。这是模板代码内主要是有用的。
告诫:当函数模板或模板类的成员函数内使用, < T1、 T2 > StaticAssertTypeEq ()是有效仅当该函数被实例化。例如,指定:
template <typename T> class Foo {
public:
void Bar() { ::testing::StaticAssertTypeEq<int, T>(); }
};
代码:
void Test1() { Foo<bool> foo; }
将不生成编译器错误,如美孚 <bool>:: Bar()从来没有真正被实例化。相反,您需要:
void Test2() { Foo<bool> foo; foo.Bar(); }
导致编译器错误。
可用性:Linux、 Windows、 Mac ;自从 1.3.0 版。
断言放置
您可以在任何 c + + 函数中使用断言。特别是,它并不一定要测试夹具类的一种方法。一个约束是生成致命故障 (失败 *和ASSERT_ *) 的断言只可在返回空的函数。这是谷歌测试不使用异常的后果。通过将它放置在你会得到一个非 void 函数混淆编译错误,像"错误: 无效的值不被忽略,应该是".
如果您需要使用一个函数,返回非 void 断言,一种选择是要改用 out 参数中返回值的函数。例如,您可以重新编写T2 Foo(T1 x)为void 美孚 (T1 x、 T2 * 结果)。您需要确保* 结果甚至当过早该函数将返回包含一些合理的价值。现在,此函数返回void,可以使用它的任何断言。
如果更改该函数的类型不是一个选项,您应当只使用生成非致命故障如, ADD_FAILURE *和EXPECT_ *的断言.
注: 构造函数和析构函数不是返回空的函数,c + + 语言规范,,所以你不能在其中使用致命的断言。如果您尝试,您将获得一个编译错误。一种简单的解决方法是将转移到返回空的私有方法的整个机体的构造函数或析构函数。但是,应该知道一个构造函数中的致命断言失败不会终止当前测试,如你的直觉可能建议 ;它只返回从构造函数早,部分建造的状态可能会导致您的对象。同样,析构函数中的致命断言失败可能会使您的对象部分破坏状态。在这些情况下,小心地使用断言 !
教学谷歌测试如何打印您的值
时 (例如, EXPECT_EQ将失败的测试断言,谷歌测试打印参数值,以帮助您调试。这是使用用户扩展值打印机。
这台打印机知道如何打印内置 c + + 类型、 本机数组、 STL 容器和支持的任何类型<<运算符。对于其他类型,它将打印原始字节的值,并希望你的用户可以搞。
如前所述,打印机是可扩展的。这意味着您可以教它更好地在印刷您特定类型比要转储的字节数。要做到这一点,定义<<为您的类型:
#include <iostream>
namespace foo {
class Bar { ... }; // We want Google Test to be able to print instances of this.
// It's important that the << operator is defined in the SAME
// namespace that defines Bar. C++'s look-up rules rely on that.
::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {
return os << bar.DebugString(); // whatever needed to print bar to os
}
} // namespace foo
有时,这可能不是一个选项: 您的团队可能会认为好的风格有<<运算符的栏或栏可能已经有<<运算符不了你想要什么 (和改变不了它)。如果是这样,而是可以定义这样一个PrintTo()函数:
#include <iostream>
namespace foo {
class Bar { ... };
// It's important that PrintTo() is defined in the SAME
// namespace that defines Bar. C++'s look-up rules rely on that.
void PrintTo(const Bar& bar, ::std::ostream* os) {
*os << bar.DebugString(); // whatever needed to print bar to os
}
} // namespace foo
如果您已经定义了两个<<和PrintTo(),后者将使用时感到关切的是谷歌测试。这允许您自定义的值如何显示在 Google 测试输出而不会影响依赖行为的代码及其<<运算符。
如果要打印自己使用谷歌测试值打印机值x ,只需要调用:: testing::PrintToString (x),它返回std::string:
vector<pair<Bar, int> > bar_ints = GetBarIntVector();
EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))
<< "bar_ints = " << ::testing::PrintToString(bar_ints);
死亡测试
在许多应用程序,有如果不满足条件,则可能会导致应用程序失败的断言。这些理智的检查,可确保该程序是在已知良好状态,是在最早可能时失败后一些程序状态已损坏。如果断言检查错误条件,该程序可能继续处于错误状态,这可能导致内存损坏、 安全漏洞或变得更糟。因此,要测试这种断言语句按预期方式工作极其重要。
因为这些先决条件检查导致死亡的过程,我们称这类测试死亡测试。一般而言,任何测试程序将终止该检查 (通过引发异常除外) 预期的方式也是死亡考验。
请注意是否一段代码引发异常,我们不认为"死亡"的死亡的测试中,如代码的调用方可以捕获此异常,避免崩溃。如果您要验证您的代码引发异常,请参见异常断言.
如果您要测试EXPECT_*()/ASSERT_*()故障测试代码中,请参见捕捉错误.
如何编写一个死亡测试
谷歌测试有支持死亡测试下面的宏:
致命的断言 | 非致命的断言 | 验证 |
ASSERT_DEATH (语句,正则表达式`); | EXPECT_DEATH (语句,正则表达式`); | 语句会崩溃,给定的错误 |
ASSERT_DEATH_IF_SUPPORTED (语句,正则表达式`); | EXPECT_DEATH_IF_SUPPORTED (语句,正则表达式`); | 如果支持死亡测试,验证该语句会崩溃,给定的错误 ;否则验证什么 |
ASSERT_EXIT (语句,谓词,正则表达式`); | EXPECT_EXIT (语句,谓词,正则表达式`); | 声明退出与给定错误并退出代码匹配谓语 |
凡语句是一个语句,预计将会导致进程死、谓语是函数或计算结果为整数的退出状态,函数对象和正则表达式是一个正则表达式 stderr 输出的预期语句匹配。注意该语句可以是任何有效的语句(包括复合语句),并不一定要在一个表达式。
和往常一样,断言变种中止当前的测试功能,而不能期待变体。
注:我们使用这个词"崩溃"在这里,意思是在进程终止与非零退出状态代码。有两种可能: 过程叫做exit ()或_exit()具有非零值,或者它可能杀死的一个信号。
这意味着如果语句终止进程退出代码 0,它就是不被视为由EXPECT_DEATH崩溃。如果真的是这样的话,或者如果要更精确地限制的退出代码,使用EXPECT_EXIT来代替。
这里的谓语必须接受int并返回布尔值。死亡测试成功,只有当该谓词,则返回true。谷歌测试定义几个谓词的处理最常见的情况:
::testing::ExitedWithCode(exit_code)
如果程序正常退出与给定的退出代码,此表达式为true 。
::testing::KilledBySignal(signal_number) // Not available on Windows.
如果该程序被杀死了给定的信号,此表达式是如此。
* _DEATH宏都方便的包装* _EXIT ,使用谓词验证进程的退出代码为非零值。
请注意死亡测试只关心三件事:
- 语句不会中止或退出过程吗?
- (在的情况下ASSERT_EXIT和EXPECT_EXIT) 的退出状态不会满足谓词吗?或者 (在ASSERT_DEATH和EXPECT_DEATH) 是退出状态非零吗?和
- stderr 输出匹配正则表达式?
特别是,如果语句生成ASSERT_ *或EXPECT_ *故障,它将不会产生死亡测试失败,如谷歌测试断言不中止进程。
若要编写一个死亡测试,只需使用您测试函数内部的上述宏之一。例如,
TEST(My*DeathTest*, Foo) {
// This death test uses a compound statement.
ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()");
}
TEST(MyDeathTest, NormalExit) {
EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success");
}
TEST(MyDeathTest, KillMyself) {
EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal");
}
验证下列内容:
- Foo(5)调用给定的错误消息,而死的过程
- 调用NormalExit()原因来打印到 stderr 和退出以退出代码为 0, "成功"的进程,并
- 调用KillMyself()杀死SIGKILL信号的过程.
测试函数体可能包含其他断言和语句,以及必要时。
重要:我们强烈建议您可以遵循公约 》 的命名测试用例 (而不是测试) * DeathTest当它包含死亡测试,如上面的示例中所示。下面的死亡测试和线程部分解释了为什么。
如果共享的测试夹具类通过正常的测试和死亡测试,您可以使用 typedef 引入的夹具类的别名,并避免重复它的代码:
class FooTest : public ::testing::Test { ... };
typedef FooTest FooDeathTest;
TEST_F(FooTest, DoesThis) {
// normal test
}
TEST_F(FooDeathTest, DoesThat) {
// death test
}
可用性:Linux,Windows (需要 MSVC 8.0 或以上),这个软件,和 Mac (后者三支持自 v1.3.0)。(ASSERT|期待) _DEATH_IF_SUPPORTED是 v1.4.0 中的新功能。
正则表达式语法
POSIX 系统 (例如 Linux,这个软件和 Mac),谷歌测试在死亡的测试中使用的POSIX 扩展正则表达式的语法。要了解有关此语法,您可能需要阅读此维基百科条目.
在 Windows 上,谷歌测试使用其自身的简单的正则表达式执行。它缺乏可以找到 POSIX 扩展正则表达式中的许多功能。例如,我们不支持联盟 ("x|y")、 分组 ("(xy)")、 方括号 ("[xy]") 和重复计数 ("x {5,7}"),除其他外。下面是我们支持 (A表示原义字符、 句点 (.) 或单\转义序列 ;x和y表示正则表达式。):
c | 匹配任何原义字符c |
\\d | 匹配任何十进制数字 |
\\D | 匹配任何字符不是十进制数字 |
\\f | \f匹配 |
来说 | 匹配\n |
\\r | 匹配\r |
\\s | 匹配任何 ASCII 空白,包括\n |
\\S | 匹配任何字符不是空白 |
\\t | \t匹配 |
\\v | \v匹配 |
\\w | 匹配任何字母、 _或十进制数字 |
\\W | 匹配任何字符, \\w不匹配 |
\\c | 匹配任何原义字符c,而后者必须是标点符号 |
. | 匹配除\n之外的任何单个字符 |
A 吗? | 匹配搜索A 0 或 1 项 |
A * | 0 或A的许多事件匹配 |
A + | 匹配A 1 或多个搜索项 |
^ | 匹配字符串的开头 (不是每行) |
$ | 匹配字符串的末尾 (不是每行) |
xy | 匹配x再跟y |
为了帮助您确定您的系统上可用的能力,谷歌测试定义宏GTEST_USES_POSIX_RE = 1时,它使用 POSIX 扩展正则表达式,或GTEST_USES_SIMPLE_RE = 1时,它使用简单的版本。如果你想你的死亡测试工作在这两种情况下,您可以对这些宏或# if或使用语法只有更多的限制。
它的工作原理
引擎盖下, ASSERT_EXIT()生成一个新的进程,并在该进程中执行死刑测试语句。详细了解如何使用的正是这种情况发生取决于平台和变量:: testing::GTEST_FLAG(death_test_style) (从命令行的标志,初始化-gtest_death_test_style).
- 在 POSIX 系统上,产卵后的孩子,使用fork() (或在 Linux 上clone () ):
- 如果该变量的值为"快速",死亡测试语句立即执行。
- 如果该变量的值为"线程",子进程重新执行单元测试二进制文件,就像最初调用它,但有一些额外的标志来导致正在考虑要运行测试只是单一死亡。
- 在 Windows 上,那孩子促成使用 API, CreateProcess() ,重新执行的二进制文件,导致只是单一死亡测试正在考虑要运行 — — 很像的线程模式对 POSIX。
其他变量的值都是非法的会造成死亡测试失败。目前,该标志的默认值是"快速"。然而,我们保留在将来会改变它的权利。因此,您的测试应不取决于此。
在任一情况下,父进程等待子进程完成,并检查,
- 孩子的退出状态满足谓语,和
- 孩子的 stderr 匹配的正则表达式。
如果死亡测试完成语句运行而不死,子进程仍将终止,并且,则断言失败。
死亡测试和线程
两个死亡测试样式的原因是线程安全的。著名的分叉线程的存在的问题,死亡测试应在单线程的上下文中运行。有时,然而,它不可行安排这样的环境。例如,静态初始化模块可能主要有史以来达到之前启动线程。一旦创建了线程,可能难以或无法清理掉它们。
谷歌测试有三种功能,旨在提高对线程问题的认识。
- 如果多个线程在运行,遇到一个死亡测试时发出警告。
- 所有其他的测试之前运行测试用例的名称以结尾的"DeathTest"。
- 它使用clone ()而不是fork()孕育子进程在 Linux 上 (clone (不可对这个软件和 Mac)), fork()是更有可能让孩子当父进程有多个线程挂起。
它是完全没有创建线程内死亡测试的声明 ;他们在一个单独的进程中执行的而不会影响父。
死亡测试样式
"线程"死亡测试样式以帮助减少风险的可能是多线程环境中测试了。该公司的股价增加的测试执行时间 (可能大大这样) 改进的线程安全。我们建议使用速度更快,默认样式"快速",除非您的测试有它的特定问题。
您可以选择特定的样式的死亡测试通过以编程方式设置该标志:
::testing::FLAGS_gtest_death_test_style = "threadsafe";
您可以设置样式的所有死亡测试二进制文件,或在单独的测试main ()中。记得标志是保存在每个测试运行之前和之后,恢复,所以你需要不能自己做。例如:
TEST(MyDeathTest, TestOne) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
// This test is run in the "threadsafe" style:
ASSERT_DEATH(ThisShouldDie(), "");
}
TEST(MyDeathTest, TestTwo) {
// This test is run in the "fast" style:
ASSERT_DEATH(ThisShouldDie(), "");
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "fast";
return RUN_ALL_TESTS();
}
需要注意的事项
ASSERT_EXIT()的语句参数可以是任何有效的 c + + 语句。如果它的叶子当前函数通过return语句或引发异常,则认为死亡测试失败了。一些谷歌测试宏可能会返回从当前函数 (如ASSERT_TRUE()),所以一定要避免这些语句中.
因为语句运行子过程中,任何在内存中的副作用 (例如修改变量,释放内存,等等) 它导致将不能观察到父进程中的。特别是,如果在释放内存死亡测试中的,您的程序将失败堆检查如父进程将永远不会看到回收的内存。要解决此问题,您可以
- 不要尝试释放内存在死亡测试 ;
- 释放的内存再次在父进程 ;或
- 不要在程序中使用的堆检查。
要实现的详细信息,由于不能将多个死亡测试断言放置在同一行 ;否则,编译将会失败并不明显的错误消息。
尽管所提供的死亡测试的"线程"风格改进的线程安全,如死锁的线程问题仍有可能使用pthread_atfork(3)注册的处理程序的存在.
在 Sub-routines 中使用断言
添加断言的痕迹
如果是测试子路径称为从几个地方,里面一个断言失败时,则很难判断哪些调用的子路径故障是从。您可以缓解此问题使用额外记录或自定义失败消息,但这通常砸你的测试。更好的解决方案是使用SCOPED_TRACE宏:
在消息可以是任何流式处理到输出。此宏将导致当前文件的名称和行号,在每个失败消息添加给定的消息。当离开当前词法范围的控制效果将被取消。
例如,
10: void Sub1(int n) {
11: EXPECT_EQ(1, Bar(n));
12: EXPECT_EQ(2, Bar(n + 1));
13: }
14:
15: TEST(FooTest, Bar) {
16: {
17: SCOPED_TRACE("A"); // This trace point will be included in
18: // every failure in this scope.
19: Sub1(1);
20: }
21: // Now it won't.
22: Sub1(9);
23: }
在邮件中的结果可能会喜欢这些:
path/to/foo_test.cc:11: Failure
Value of: Bar(n)
Expected: 1
Actual: 2
Trace:
path/to/foo_test.cc:17: A
path/to/foo_test.cc:12: Failure
Value of: Bar(n + 1)
Expected: 2
Actual: 3
无影无踪,它会一直难知道哪些调用Sub1()分别两次的失败来的。(您可以添加一个额外的消息以指示值n, Sub1()中每个说法,但这是乏味)。
使用SCOPED_TRACE的一些提示:
- 使用适当的消息,很多时候足够使用SCOPED_TRACE开头的子路径,而不是在每个调用站点。
- 当调用 sub-routines 循环内的,在SCOPED_TRACE中使消息的循环迭代器一部分,你可以知道失败是从哪个迭代。
- 有时跟踪点的行号是足够的识别特定调用的子路径。在这种情况下,您不必为SCOPED_TRACE选择唯一的消息。您可以只使用"".
- 您可以使用SCOPED_TRACE内部范围中时,外部范围里有一个。在这种情况下,所有活动跟踪点将包括在失败消息,他们遇到了以相反的顺序。
- 跟踪转储是 Emacs 的编译缓冲区中可点击 — — 该行在源文件中就会返回一个行号和你打 !
可用性:Linux、 Windows、 mac。
传播致命故障
当使用ASSERT_ *和失败 *不理解,他们失败时的一个常见缺陷他们只能中止当前函数,不整的测试。例如,下面的测试将 segfault:
void Subroutine() {
// Generates a fatal failure and aborts the current function.
ASSERT_EQ(1, 2);
// The following won't be executed.
...
}
TEST(FooTest, Bar) {
Subroutine();
// The intended behavior is for the fatal failure
// in Subroutine() to abort the entire test.
// The actual behavior: the function goes on after Subroutine() returns.
int* p = NULL;
*p = 3; // Segfault!
}
我们不使用异常,因为它是技术上不可能实现在这里是预期的行为。为纾缓这种情况,谷歌测试提供了两种解决方案。您可以使用 (ASSERT| 或期待) _NO_FATAL_FAILURE断言或HasFatalFailure()函数。他们介绍了以下两个小节。
子例程的断言
如上所示,如果您的测试调用一个子程序,有ASSERT_ *失败,测试将继续该子例程返回后。这可能不是你想要什么。
人们常常希望像异常传播致命故障。这对于谷歌测试提供下面的宏:
致命的断言 | 非致命的断言 | 验证 |
ASSERT_NO_FATAL_FAILURE (语句); | EXPECT_NO_FATAL_FAILURE (语句); | 当前线程中的语句不会生成任何新的致命故障。 |
仅在线程执行断言失败进行检查以确定这种类型的断言的结果。如果语句创建新的线程,则忽略这些线程中的故障。
示例:
ASSERT_NO_FATAL_FAILURE(Foo());
int i;
EXPECT_NO_FATAL_FAILURE({
i = Bar();
});
可用性:Linux、 Windows、 mac。目前不支持从多个线程的断言。
检查当前测试失败
在HasFatalFailure() :: testing::Test类返回true ,如果当前测试中的断言受到了致命的失败。这将允许函数来捕获子路径中的致命失误和提早回来。
class Test {
public:
...
static bool HasFatalFailure();
};
典型的用法,基本上模拟引发的行为,是异常的:
TEST(FooTest, Bar) {
Subroutine();
// Aborts if Subroutine() had a fatal failure.
if (HasFatalFailure())
return;
// The following won't be executed.
...
}
如果HasFatalFailure() TEST() 、 TEST_F() 、 或测试夹具的外部使用,您必须添加:: testing::Test::前缀,例如:
if (::testing::Test::HasFatalFailure())
return;
同样, HasNonfatalFailure()返回true ,如果当前测试具有至少一个非致命故障,并且HasFailure()返回true ,如果当前测试有两种至少一个故障。
可用性:Linux、 Windows、 mac。1.4.0 版本以来, HasNonfatalFailure()和HasFailure()都可。
日志记录的其他信息
在测试代码中,您可以调用RecordProperty ("密钥"值)登录的其他信息,值可以是 C 字符串或一个 32 位整数。如果您指定一个密钥的记录的最后一个值将激发到 XML 输出。例如,测试
TEST_F(WidgetUsageTest, MinAndMaxWidgets) {
RecordProperty("MaximumWidgets", ComputeMaxUsage());
RecordProperty("MinimumWidgets", ComputeMinUsage());
}
将输出 XML,像这样:
...
<testcase name="MinAndMaxWidgets" status="run" time="6" classname="WidgetUsageTest"
MaximumWidgets="12"
MinimumWidgets="9" />
...
请注意:
- RecordProperty()是测试类的静态成员。因此它需要使用作为前缀:: testing::Test::如果测试身体和测试夹具类以外的使用。
- 密钥必须是有效的 XML 属性名称,并不能与那些已经使用的谷歌测试 (名称、状态、时间和类名冲突).
可用性: Linux、 Windows、 mac。
测试在同一测试用例之间的资源共享
谷歌测试创建一个新的测试夹具对象,每个测试为了使测试独立并更易于调试。不过,有时测试使用资源,价格昂贵,成立一个副本每测试模型制作费用高昂。
如果测试不更改资源,则它们共享单个资源副本没有害处。因此,在每个测试集-上/泪下,谷歌测试还支持每个测试案例集-上/撤展。要使用它:
- 在测试夹具类 (说生成器) 中,定义为静态一些成员变量来保存共享的资源。
- 在同一测试夹具类,定义一个静态 void SetUpTestCase()函数 (不到同一个小u拼写为SetupTestCase请记住 !) 成立,拆毁他们的共享的资源和静态 void TearDownTestCase()函数。
就是这个 !谷歌测试自动运行生成器测试用例中的第一次测试(即前创建的第一个生成器对象) 之前, 调用SetUpTestCase()和TearDownTestCase()调用后 (即后删除最后一个生成器对象) 在它运行最后的测试。之间,这些测试可以使用的共享的资源。
记得测试顺序是未定义的所以您的代码不能取决于之前或之后另一个测试。此外,测试必须要么不修改任何的状态共享资源,或如果他们做修改状态,他们必须状态还原到其原始值之前将控制传递给下一次的测试。
下面是一个示例设置每个测试案例和撤展:
class FooTest : public ::testing::Test {
protected:
// Per-test-case set-up.
// Called before the first test in this test case.
// Can be omitted if not needed.
static void SetUpTestCase() {
shared_resource_ = new ...;
}
// Per-test-case tear-down.
// Called after the last test in this test case.
// Can be omitted if not needed.
static void TearDownTestCase() {
delete shared_resource_;
shared_resource_ = NULL;
}
// You can define per-test set-up and tear-down logic as usual.
virtual void SetUp() { ... }
virtual void TearDown() { ... }
// Some expensive resource shared by all tests.
static T* shared_resource_;
};
T* FooTest::shared_resource_ = NULL;
TEST_F(FooTest, Test1) {
... you can refer to shared_resource here ...
}
TEST_F(FooTest, Test2) {
... you can refer to shared_resource here ...
}
可用性:Linux、 Windows、 mac。
全局设置和撤展
正如您可以设置和撤展测试级别和测试用例一级,你也可以做在测试程序级别。这里是如何。
第一,你子类:: testing::Environment类定义一个测试环境,知道如何设置和撤展:
class Environment {
public:
virtual ~Environment() {}
// Override this to define how to set up the environment.
virtual void SetUp() {}
// Override this to define how to tear down the environment.
virtual void TearDown() {}
};
然后,注册您的环境类的实例的谷歌测试通过调用:: testing::AddGlobalTestEnvironment()函数:
Environment* AddGlobalTestEnvironment(Environment* env);
现在,当调用RUN_ALL_TESTS()时,它首先调用SetUp()方法的环境对象,然后运行测试,如果有没有致命的失败,最后调用TearDown()环境对象。
它是确定以注册多个环境对象。在这种情况下,将调用其SetUp()顺序他们都注册后,并将调用其TearDown()相反的顺序。
请注意 Google 测试需要注册的环境对象的所有权。通过你自己,因此请不要删除它们。
RUN_ALL_TESTS()调用之前,可能在main ()中,则应调用AddGlobalTestEnvironment() 。如果您使用gtest_main,您需要把这称之为main ()开始为其生效之前。执行此操作的一种方法是定义一个全局变量,像这样:
::testing::Environment* const foo_env = ::testing::AddGlobalTestEnvironment(new FooEnvironment);
然而,我们强烈建议您编写您自己的main () ,然后调用AddGlobalTestEnvironment() ,依靠初始化的全局变量会使代码难以阅读,当您注册多个不同的翻译单位从环境和环境问题的原因可能有他们 (请记住,编译器并不能保证在其中不同的翻译单位从全局变量进行初始化的顺序) 之间的依赖关系。
可用性:Linux、 Windows、 mac。
值参数化测试
值参数测试让您可以测试您的代码使用不同的参数,而无需编写相同的测试的多个副本。
假设您编写测试您的代码,然后实现您的代码受布尔命令行标志的存在。
TEST(MyCodeTest, TestFoo) {
// A code to test foo().
}
通常人们他们的测试代码考虑中这种情况下的布尔参数的函数。该函数设置的标志,然后执行的测试的代码。
void TestFooHelper(bool flag_value) {
flag = flag_value;
// A code to test foo().
}
TEST(MyCodeTest, TestFooo) {
TestFooHelper(false);
TestFooHelper(true);
}
但此安装程序有严重的缺陷。首先,当您在测试中,测试断言失败时,它将成为不清楚哪些该参数的值导致失败。你可以到你的期望流澄清消息 /ASSERT语句,但你得去做它们。第二,你要添加的每个测试的这样一个 helper 函数。如果您有十个测试吗?二十吗?百名?
值参数测试会让你只有一次写入您的测试然后轻松地实例化并运行它的任意数量的参数值。
值参数测试来方便时,下面是一些其他情况:
- 您要测试的面向对象的接口的不同实现湾。
- 要测试您的代码在各种输入 (即数据驱动测试)。此功能很容易被滥用,所以请锻炼你的良好感觉时做这件事 !
如何编写测试参数值
第一次写值参数测试,应定义夹具的类。必须从两个:: testing::Test和:: testing::WithParamInterface <T> (后者是一个纯粹的界面),其中T是您的参数值的类型。为方便起见,您可以只是派生的夹具类从:: testing::TestWithParam <T>,其本身从两个:: testing::Test和:: testing::WithParamInterface <T>。T可以是任何 copyable 的类型。如果是原始指针,您负责管理的尖锐的值的寿命。
class FooTest : public ::testing::TestWithParam<const char*> {
// You can implement all the usual fixture class members here.
// To access the test parameter, call GetParam() from class
// TestWithParam<T>.
};
// Or, when you want to add parameters to a pre-existing fixture class:
class BaseTest : public ::testing::Test {
...
};
class BarTest : public BaseTest,
public ::testing::WithParamInterface<const char*> {
...
};
然后,使用TEST_P宏来定义使用这种装置所需的任意多个测试模式。_P后缀为"参数化"或"图案",您认为可以随意选择。
TEST_P(FooTest, DoesBlah) {
// Inside a test, access the test parameter with the GetParam() method
// of the TestWithParam<T> class:
EXPECT_TRUE(foo.Blah(GetParam()));
...
}
TEST_P(FooTest, HasBlahBlah) {
...
}
最后,您可以使用INSTANTIATE_TEST_CASE_P来实例化采用任何一组参数,您想要的测试用例。谷歌测试定义函数生成测试参数的数量。他们返回我们称之为 (惊喜 !)参数发电机。下面是他们,所有测试命名空间中的摘要:
范围 (开始,结束 [、 步]) | 收益率值{开始,开始 + 步、 开始 + 步 + 步、 … …}。值不包括结束。一步默认为 1。 |
值 (v1、 v2,… …,vN) | 收益率值{v1、 v2,… …,vN}. |
ValuesIn(container)和ValuesIn(begin, end) | C 样式数组、 风格 STL 容器或迭代器范围从收益率值[begin, end)。容器、开始和结束可以在运行时决定值的表达式。 |
Bool() | 收益率序列{虚假的、 真实的}. |
结合 (g1、 g2,… …,gN) | (数学头脑的笛卡儿积) N生成器生成的值的所有组合的收益都率。这只是可用的如果您的系统提供< tr1/元组 >头。如果您确信您的系统,而且谷歌测试不同意,可以通过定义覆盖GTEST_HAS_TR1_TUPLE = 1。注释中include/gtest/internal/gtest-port.h的详细信息,请参阅。 |
有关更多详细信息,请参阅定义这些函数的源代码中的注释.
下面的语句将实例化生成器测试用例每个参数的值"meeny"、 "调节器"、 和"教育部"从测试.
INSTANTIATE_TEST_CASE_P(InstantiationName,
FooTest,
::testing::Values("meeny", "miny", "moe"));
若要区分不同的模式实例 (是的您可以实例化它不止一次), INSTANTIATE_TEST_CASE_P的第一个参数是将被添加到实际测试用例名称的前缀。记得选择的不同实例的唯一前缀。从上面的实例化的测试将这些名称:
- InstantiationName/FooTest.DoesBlah/0为"meeny"
- InstantiationName/FooTest.DoesBlah/1的"调节器"
- InstantiationName/FooTest.DoesBlah/2为"教育部"
- InstantiationName/FooTest.HasBlahBlah/0为"meeny"
- InstantiationName/FooTest.HasBlahBlah/1的"调节器"
- InstantiationName/FooTest.HasBlahBlah/2为"教育部"
您可以使用这些名称在-gtest_filter.
此语句将实例化的所有测试从生成器,每个参数的值"猫"和"狗":
const char* pets[] = {"cat", "dog"};
INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest,
::testing::ValuesIn(pets));
从上面的实例化的测试将这些名称:
- AnotherInstantiationName/FooTest.DoesBlah/0为"猫"
- AnotherInstantiationName/FooTest.DoesBlah/1为"狗"
- AnotherInstantiationName/FooTest.HasBlahBlah/0为"猫"
- AnotherInstantiationName/FooTest.HasBlahBlah/1为"狗"
请注意INSTANTIATE_TEST_CASE_P将实例化给定的测试用例、 它们的定义是否来之前或之后的INSTANTIATE_TEST_CASE_P语句中的所有测试。
你可以看到这些文件以进行更多的例子。
可用性: Linux,Windows (需要 MSVC 8.0 或以上),Mac ;自从版本 1.2.0。
创建参数值化抽象测试
在以上所述,我们定义并实例化生成器在同一源文件中。有时,您可能希望库中定义的值参数测试,让它们进行实例化后的其他人。这种模式被称为抽象测试。作为其应用程序的一个例子,设计接口时您可以编写一套标准 (可能作为测试参数使用工厂函数) 的抽象测试接口的实现都有望通过。当一个人实现接口时,他可以实例化你免费获取所有接口一致性测试套件。
若要定义抽象的测试,应组织你像这样的代码:
- 头文件中定义的参数化的测试夹具类 (例如生成器), foo_param_test.h说。认为这是声明您抽象的测试。
- 在foo_param_test.cc,其中包括foo_param_test.h TEST_P定义。认为这是实施论文摘要的测试。
一旦定义,您可以实例化这些包括foo_param_test.h、 调用INSTANTIATE_TEST_CASE_P(),和foo_param_test.cc的链接。您可以实例化抽象同一测试用例多次,有可能在不同的源文件中。
类型化的测试
假设您有多个相同的接口的实现,并希望确保所有人都满足一些常见的要求。或者,您可能定义了应该符合相同的"概念"的几种类型和您要验证它。在这两种情况下,您希望为不同类型重复相同的测试逻辑。
虽然您可以为每种类型编写一个测试或TEST_F要测试 (和你甚至可能影响您的测试从调用的函数模板测试逻辑),过程繁琐,不能扩展: 如果要测试m n类型,你最终会从事写作m * n 测试s。
Typed 测试允许您重复相同的逻辑测试类型的列表。你只需要编写测试逻辑一次,尽管你必须知道类型列表中写入时键入的测试。下面是你怎么做:
首先,定义夹具类模板。它应由类型参数化。记住要从它派生:: testing::Test:
template <typename T>
class FooTest : public ::testing::Test {
public:
...
typedef std::list<T> List;
static T shared_;
T value_;
};
接下来,与测试用例,将重复的列表中的每个类型的关联类型的列表:
typedef ::testing::Types<char, int, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);
必须正确地解析TYPED_TEST_CASE宏typedef 。否则,编译器会认为在类型列表中的每个逗号引入了新的宏参数。
然后,使用TYPED_TEST()的TEST_F()而不是定义类型化的测试,这个测试案例。您可以重复此步骤要多少倍:
TYPED_TEST(FooTest, DoesBlah) {
// Inside a test, refer to the special name TypeParam to get the type
// parameter. Since we are inside a derived class template, C++ requires
// us to visit the members of FooTest via 'this'.
TypeParam n = this->value_;
// To visit static members of the fixture, add the 'TestFixture::'
// prefix.
n += TestFixture::shared_;
// To refer to typedefs in the fixture, add the 'typename TestFixture::'
// prefix. The 'typename' is required to satisfy the compiler.
typename TestFixture::List values;
values.push_back(n);
...
}
TYPED_TEST(FooTest, HasPropertyA) { ... }
你可以看到一个完整的示例为samples/sample6_unittest.cc 。
可用性:Linux,Windows (需要 MSVC 8.0 或以上),Mac ;自从 1.1.0 版。
类型参数的测试
就像是参数化类型的测试类型的测试中,只是他们不需要你知道时间提前的类型的列表。相反,可以首先定义测试逻辑和后来实例与不同类型列表。你可以甚至其实例化不止一次在同一程序中。
如果您正在设计接口或概念,您可以定义一套验证任何有效实现的接口/概念应具有的属性类型参数测试。然后,每个实现的作者可以只是实例化他以验证它符合要求,而无需反复编写类似测试类型的测试套件。下面是一个示例:
首先,定义夹具类模板,像我们那样类型的测试:
template <typename T>
class FooTest : public ::testing::Test {
...
};
下一步,声明您将定义一个类型参数测试用例:
TYPED_TEST_CASE_P(FooTest);
_P后缀为"参数化"或"图案",您认为可以随意选择。
然后,使用TYPED_TEST_P()来定义一个类型参数测试。您可以重复此步骤要多少倍:
TYPED_TEST_P(FooTest, DoesBlah) {
// Inside a test, refer to TypeParam to get the type parameter.
TypeParam n = 0;
...
}
TYPED_TEST_P(FooTest, HasPropertyA) { ... }
现在最为棘手的部分: 您需要注册使用REGISTER_TYPED_TEST_CASE_P宏之前可以对它们进行实例化的所有测试模式。宏的第一个参数是测试用例的名称 ;其余都是这个测试案例中的测试的名称:
REGISTER_TYPED_TEST_CASE_P(FooTest,
DoesBlah, HasPropertyA);
最后,你可以自由地进行实例化的模式与所需的类型。如果你把上面的代码的头文件中,则可以# include它在多个 c + + 源代码文件并将其实例化多次。
typedef ::testing::Types<char, int, unsigned int> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
为了区分不同实例, INSTANTIATE_TYPED_TEST_CASE_P宏的第一个参数是模式的将被添加到实际测试用例名称的前缀。记得选择的不同实例的唯一前缀。
在类型列表中包含只有一种类型的特殊情况下,您可以直接而编写该类型:: testing::Types <>...,像这样:
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
你可以看到一个完整的示例为samples/sample6_unittest.cc 。
可用性:Linux,Windows (需要 MSVC 8.0 或以上),Mac ;自从 1.1.0 版。
测试私有代码
如果您更改内部实现您的软件,您的测试应不打破,只要更改不是由用户可以观察到。因此,每个黑盒测试的原则,大部分的时间您应该测试您通过其公共接口的代码。
如果您仍然发现自己需要测试内部实现的代码,考虑是否有更好的设计,就不需要这样做。如果您绝对有虽然测试非公共接口代码,您就可以了。有两种情况,要考虑:
- 静态函数 (不相同,静态成员函数 !) 或未命名的命名空间,及
- 私有或受保护的类成员
静态函数
静态函数和一个未命名的命名空间中的定义/声明都只是在同一个翻译单元内可见。若要测试它们,您可以# include正在测试您的*_test.cc文件中的整个.cc文件。(# 包括.cc文件不是重用代码的好方法-您不应将这样做在生产代码中) !
然而,更好的方法是将私有代码移动到foo::internal命名空间,其中美孚是项目通常使用,该命名空间,把私有的声明放在*-internal.h文件。允许您生产.cc文件和您的测试包括此内部的标头,但并不是您的客户端。这种方式,您可以全面测试您的内部实现无泄漏它向您的客户端。
类的私有成员
仅在类中或通过朋友从访问私有类成员。要访问类的私有成员,可以将您的测试夹具声明为类的朋友并在装备中定义的访问者。然后,测试使用夹具可以访问通过访问器在夹具生产类的私有成员。注意即使您夹具生产类的朋友,你的测试不是自动的朋友,从技术上讲夹具的子类中定义它们。
另一种方法来测试私有成员是重构他们实现类,然后在中声明为*-internal.h文件。您的客户端不允许包括此标头,但您的测试可以。这种被称为平普尔 (私人执行) 成语。
或者,您可以通过在类体中添加这行声明单个测试作为您的类的朋友:
FRIEND_TEST(TestCaseName, TestName);
例如,
// foo.h
#include "gtest/gtest_prod.h"
// Defines FRIEND_TEST.
class Foo {
...
private:
FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
int Bar(void* x);
};
// foo_test.cc
...
TEST(FooTest, BarReturnsZeroOnNull) {
Foo foo;
EXPECT_EQ(0, foo.Bar(NULL));
// Uses Foo's private member Bar().
}
特别注意在命名空间中,定义您的类时,应定义您的测试夹具和测试在同一命名空间中如果您希望它们成为您的类的朋友。例如,如果要测试的代码看起来,如:
namespace my_namespace {
class Foo {
friend class FooTest;
FRIEND_TEST(FooTest, Bar);
FRIEND_TEST(FooTest, Baz);
...
definition of the class Foo
...
};
} // namespace my_namespace
测试代码应类似:
namespace my_namespace {
class FooTest : public ::testing::Test {
protected:
...
};
TEST_F(FooTest, Bar) { ... }
TEST_F(FooTest, Baz) { ... }
} // namespace my_namespace
捕捉失败
如果您正在构建一个测试的实用程序,谷歌测试的顶部,您要测试您的实用程序。你会使用什么框架对它进行测试?谷歌测试的课程。
挑战是要验证您的测试实用程序正确报告故障。通过引发异常报告失败的框架,可以捕获此异常,断言它。但 Google 测试不使用异常,那么,如何做我们测试一段代码生成一个预期的故障?
"gtest/gtest-spi.h"包含一些构造来执行此操作。# 包括此标头后,可以使用
EXPECT_FATAL_FAILURE (语句,子字符串); |
断言语句生成致命 (例如ASSERT_ *) 失败的消息中包含给定的的子字符串或使用
EXPECT_NONFATAL_FAILURE (语句,子字符串); |
如果你期望非致命 (例如EXPECT_ *) 故障。
由于技术原因,有一些注意事项:
- 您不能流到任一宏失败消息。
- EXPECT_FATAL_FAILURE()中的语句不能引用非静态局部变量或该对象的非静态成员。
- EXPECT_FATAL_FAILURE()中的语句不能返回值。
注:谷歌测试的设计头脑中的线程。一旦已经实现了"gtest/internal/gtest-port.h"中的同步基元,谷歌测试将成为线程安全的也就是说然后可以使用断言在多个线程同时。在前
但是,谷歌测试只支持单线程的使用情况。一旦线程安全的EXPECT_FATAL_FAILURE()和EXPECT_NONFATAL_FAILURE()将捕获仅当前线程中的故障。如果语句创建新的线程,这些线程中的失误将被忽略。如果您要捕获所有线程从失败相反,则应使用下面的宏:
EXPECT_FATAL_FAILURE_ON_ALL_THREADS (语句,子字符串); |
EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS (语句,子字符串); |
获取当前测试名称
有时一个功能可能需要知道的当前正在运行的测试的名称。例如,您可能会使用您测试夹具的SetUp()方法设置基于运行的测试的金色文件名称。:: Testing::TestInfo类有此信息:
namespace testing {
class TestInfo {
public:
// Returns the test case name and the test name, respectively.
//
// Do NOT delete or free the return value - it's managed by the
// TestInfo class.
const char* test_case_name() const;
const char* name() const;
};
} // namespace testing
要获得一个TestInfo对象的当前正在运行的测试,请致电
current_test_info()对单元测试singleton 对象:
// Gets information about the currently running test.
// Do NOT delete the returned object - it's managed by the UnitTest class.
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
printf("We are in test %s of test case %s.\n",
test_info->name(), test_info->test_case_name());
如果没有测试运行current_test_info()则返回空指针。特别是在TestCaseSetUp()、 TestCaseTearDown() (你知道测试用例名称隐式) 或从这些调用的函数无法找到测试用例名称。
可用性:Linux、 Windows、 mac。
通过处理测试事件扩大谷歌测试
谷歌测试提供了一个事件侦听器的 API让您接收测试程序的有关进展情况通知和测试失败。你可以听的开始和结束的测试程序、 测试用例或一种测试方法,其中包括事件。您可以使用此 API 来补充或替换标准控制台输出,替换 XML 输出,或提供完全不同形式的输出,如一个 GUI 或数据库。您也可以实现资源泄漏检查器中,例如,将检测事件用作检查站。
可用性:Linux、 Windows、 Mac ;自从 v1.4.0。
定义事件侦听器
要定义一个事件侦听器,你子类或testing::TestEventListener或testing::EmptyTestEventListener。前者是 (抽象) 接口,其中每个纯虚方法可以重写,以处理测试事件(例如,在测试开始, OnTestStart()方法将被调用时。)。后者提供这样一个子类只需要重写的方法,它关心空在界面中,所有方法的实现。
当触发事件时,其上下文将作为参数传递给处理程序函数。使用以下参数类型:
事件处理函数可以检查它接收到找出有趣事件和测试程序的状态信息的参数。下面是一个示例:
class MinimalistPrinter : public ::testing::EmptyTestEventListener {
// Called before a test starts.
virtual void OnTestStart(const ::testing::TestInfo& test_info) {
printf("*** Test %s.%s starting.\n",
test_info.test_case_name(), test_info.name());
}
// Called after a failed assertion or a SUCCEED() invocation.
virtual void OnTestPartResult(
const ::testing::TestPartResult& test_part_result) {
printf("%s in %s:%d\n%s\n",
test_part_result.failed() ? "*** Failure" : "Success",
test_part_result.file_name(),
test_part_result.line_number(),
test_part_result.summary());
}
// Called after a test ends.
virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
printf("*** Test %s.%s ending.\n",
test_info.test_case_name(), test_info.name());
}
};
使用事件侦听器
若要使用已定义的事件侦听器,将它的实例添加到 Google 测试事件侦听器列表 (由类TestEventListeners -表示名称的末尾注意"s") 在main ()函数中,之前调用RUN_ALL_TESTS():
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
// Gets hold of the event listener list.
::testing::TestEventListeners& listeners =
::testing::UnitTest::GetInstance()->listeners();
// Adds a listener to the end. Google Test takes the ownership.
listeners.Append(new MinimalistPrinter);
return RUN_ALL_TESTS();
}
只有一个问题: 默认测试结果打印机是仍在影响,所以它的输出将混入简约打印机的输出。若要取消默认打印机,只是释放它从事件侦听器列表中,然后删除它。您可以通过添加一行:
...
delete listeners.Release(listeners.default_result_printer());
listeners.Append(new MinimalistPrinter);
return RUN_ALL_TESTS();
现在,坐下来,享受你的测试从完全不同的输出结果。有关更多详细信息,您可以阅读此示例.
您可将多个侦听器追加到列表中。当触发On*Start()或OnTestPartResult()事件时,听众将接收它 (因为新侦听器添加到列表中,文本的默认打印机的结尾和默认 XML 生成器将首先接收事件) 出现在列表中的顺序。On*End()的事件就会收到相反的顺序侦听器。这样,以后添加到被陷害先前添加侦听器的输出的侦听器的输出。
在听众中生成失败
您可以使用故障提高宏 (EXPECT_*()、 ASSERT_*()、 FAIL()等) 时处理事件。有一些限制:
- 您不能在OnTestPartResult()中生成任何故障 (否则会造成以递归方式调用OnTestPartResult() )。
- 不允许一个侦听器,处理OnTestPartResult()生成任何故障。
将侦听器添加到侦听器列表中时,你应该把处理OnTestPartResult() 前听众能够生成失败的侦听器。这可以确保故障产生的后者由于前正确的测试。
我们有一个样本的故障提高监听器在这里.
正在运行的测试程序: 高级的选项
谷歌测试测试程序是普通的可执行文件。一旦建立,可以直接运行它们,并影响他们通过下列环境变量和/或命令行标志的行为。对于工作的标志,您的程序必须调用:: testing::InitGoogleTest()之前调用RUN_ALL_TESTS().
若要查看受支持的标志和它们的用法的列表,请运行您的测试程序与— — 帮助标志。您还可以使用-h, -吗?,或/?简称。1.3.0 版中添加此功能。
如果选项指定的环境变量和一个标志,后者将优先。大多数选项也可以在代码中设置/读取: 访问命令行标志的值-gtest_foo,写:: testing::GTEST_FLAG(foo)。通用模式是设置在调用标志的值:: testing::InitGoogleTest()更改默认值的标记:
int main(int argc, char** argv) {
// Disables elapsed time by default.
::testing::GTEST_FLAG(print_time) = false;
// This allows the user to override the flag on the command line.
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
选择测试
此部分将显示选择要运行的测试的各种选项。
列出测试名称
有时是之前运行它们,这样,可以应用一个筛选器,如果需要列出的程序中可用的测试。包括船旗-gtest_list_tests重写所有其他标志并列出以下格式的测试:
TestCase1.
TestName1
TestName2
TestCase2.
TestName
实际运行如果提供了该标记没有列出的测试。没有相应的环境变量,此标志。
可用性:Linux、 Windows、 mac。
运行测试的子集
默认情况下,谷歌测试程序运行用户已定义的所有测试。有时,您想运行只测试 (例如调试或快速验证更改) 的子集。如果您设置环境变量,GTEST_FILTER或-gtest_filter只运行的测试的完整名称 (在TestCaseName.TestName的形式) 与筛选器匹配的筛选器字符串,谷歌测试将该标志。
筛选器的格式是 ':'-'-',另一个分隔的列表的通配符模式 (称为正面图案) 也可以跟着':'-分离的模式列表中 (称为负模式)。测试与筛选器相匹配,当且仅当它与任何积极的模式相匹配,但是并不匹配任何负面模式。
一种模式可以包含' *' (匹配任何字符串) 或' 吗? '(匹配任意单个字符)。为方便起见,筛选器' *-NegativePatterns 的也写成'-NegativePatterns 的.
例如:
- 。 / foo_test有没有标志,并因此运行所有的测试。
- 。 / foo_test-gtest_filter = *此外可以运行一切,因到单个匹配-一切*的值。
- 。 / foo_test-gtest_filter = 生成器。 *运行测试用例生成器中的一切.
- 。 / foo_test-gtest_filter = * Null *: * 构造函数 *运行任何测试的完整名称中包含"空"或"建设者".
- 。 / foo_test-gtest_filter =-* DeathTest。 *运行所有非死亡测试。
- 。 / foo_test-gtest_filter = 生成器。 *-FooTest.Bar一切都运行在测试用例生成器 FooTest.Bar除外.
可用性:Linux、 Windows、 mac。
暂时禁用的测试
如果你不能马上解决的破断的试验,您可以添加DISABLED_前缀为其名称。这将从执行排除它。这是优于注释代码或使用# if 0,如禁用的测试仍在编译 (和因此不会腐烂)。
如果您需要禁用所有测试的测试用例,你可以将DISABLED_添加到前面的、 每个测试的名称或或者将其添加到前面的测试用例名称。
例如,以下测试不会运行谷歌试验,即使他们仍将被编译:
// Tests that Foo does Abc.
TEST(FooTest, DISABLED_DoesAbc) { ... }
class DISABLED_BarTest : public ::testing::Test { ... };
// Tests that Bar does Xyz.
TEST_F(DISABLED_BarTest, DoesXyz) { ... }
注:此功能仅用于暂时缓解疼痛。您仍然要修复在晚些时候已禁用的测试。作为提醒,谷歌测试将打印横幅警告你,如果一个测试程序包含任何已禁用的测试。
提示:您可以很容易计算的已禁用的测试,您必须使用grep数。此数字可以用作度量改进您的测试质量。
可用性:Linux、 Windows、 mac。
临时启用已禁用的测试
要执行测试中包含禁用的测试,只是调用测试程序与-gtest_also_run_disabled_tests标志或GTEST_ALSO_RUN_DISABLED_TESTS环境变量设置为0以外的值。您可以将此组合-gtest_filter标志进一步选择其中禁用要运行的测试。
可用性:Linux、 Windows、 Mac ;自从 1.3.0 版。
重复测试
偶尔,你可能会遇到一个测试,其结果是时好时坏。也许它将失败的时候,使它很难重现 bug 在调试器下的只有 1%。这可以是挫折的主要来源。
-Gtest_repeat标志,可以重复所有 (或选定) 在一个程序中多次测试方法。我希望,片状试验最终将失败,并给你一个机会来调试。下面是如何使用它:
$ foo_test-gtest_repeat = 1000年 | 重复 foo_test 1000 倍,不要只失败。 |
$ foo_test-gtest_repeat = 1 | 负计数意味着永远重复。 |
$ foo_test-gtest_repeat = 1000-gtest_break_on_failure | 重复 foo_test 1000 倍,停在第一次的失败。在调试器下运行时,这一点尤为有用: 当 testfails,它会放到调试器,然后可以检查变量和堆栈。 |
$ foo_test-gtest_repeat = 1000-gtest_filter = FooBar | 重复的测试,其名称与筛选器匹配 1000年倍。 |
如果您的测试程序包含全局设置上/泪下代码注册使用AddGlobalTestEnvironment(),它将会以及强光下中,或许是因为重复在每次迭代。您还可以通过设置GTEST_REPEAT环境变量指定了重复计数。
可用性:Linux、 Windows、 mac。
改组测试
您可以指定-gtest_shuffle标志 (或设置为1 GTEST_SHUFFLE环境变量) 以随机顺序程序中运行的测试。这有助于揭示坏测试之间的依赖性。
默认情况下,Google 测试使用随机种子从当前时间计算。因此你会得到不同的顺序每次。控制台输出包括随机种子值,这样您可以稍后重现订单相关测试失败。显式指定的随机种子,请使用-gtest_random_seed = 种子标记 (或设置GTEST_RANDOM_SEED环境变量),其中种子是介于 0 和 99999 之间的一个整数。种子值 0 是特殊: 它告诉 Google Test 做计算的种子从当前时间的默认行为。
如果你把这与-gtest_repeat = N,谷歌测试将挑选不同的随机种子和 re-shuffle 在每次迭代的测试。
可用性:Linux、 Windows、 Mac ;自从 v1.4.0。
控制测试输出
这一节教如何调整测试结果报告的方式。
彩色终端输出
谷歌测试可以输出,以使它更易于魔之间的测试中,分离其终端中使用的颜色和是否测试通过。
您可以将 GTEST_COLOR 环境变量设置或设置-gtest_color命令行标志,是的没有,或自动(默认) 启用颜色、 禁用颜色,或让谷歌测试决定。当且仅当输出去一个终端,(非 Windows 平台) 上学期环境变量设置为xterm或xterm 颜色值时自动,谷歌测试程序将使用的颜色.
可用性:Linux、 Windows、 mac。
抑制所经过的时间
默认情况下,Google 测试打印每个测试运行的时间。若要取消的运行测试程序与-gtest_print_time = 0命令行的标志。GTEST_PRINT_TIME环境变量设置为0 ,具有相同的效果。
可用性:Linux、 Windows、 mac。(在谷歌测试 1.3.0 和较低,默认行为是已用的时间不打印)。
生成 XML 报告
谷歌测试可以发出一份详细的 XML 报告在其正常文本输出文件。报告包含每个测试的持续时间,从而可以帮助您识别速度慢的测试。
若要生成 XML 报表,设置GTEST_OUTPUT环境变量或-gtest_output字符串"xml:_path_to_output_file_",这将在给定位置创建文件的标志。也可以使用字符串"xml",可以在当前目录中的test_detail.xml文件中发现案件输出。
如果您指定的目录 (例如, "xml:output/目录 /"在 Linux 上) 或"xml:output\directory\"在 Windows 上,谷歌测试将创建的 XML 文件,在该目录中,测试的可执行文件 (例如foo_test.xml的测试程序foo_test或foo_test.exe) 的名字命名的。如果该文件已经存在 (也许遗留在上次运行),谷歌测试将选择一个不同的名称 (例如foo_test_1.xml) 以避免覆盖它。
该报表在这里使用规定的格式。它基于junitreport Ant 任务,并可以由哈得逊河像流行连续生成系统分析。由于这种格式原来打算用于 Java,一点解释是需要使其适用于谷歌测试的测试中,如下所示:
<testsuites name="AllTests" ...>
<testsuite name="test_case_name" ...>
<testcase name="test_name" ...>
<failure message="..."/>
<failure message="..."/>
<failure message="..."/>
</testcase>
</testsuite>
</testsuites>
- <testsuites>的根元素对应于整个测试程序。
- <testsuite>元素对应于谷歌测试测试用例。
- <testcase>元素对应于谷歌测试测试功能。
例如,下面的程序
TEST(MathTest, Addition) { ... }
TEST(MathTest, Subtraction) { ... }
TEST(LogicTest, NonContradiction) { ... }
无法生成此报告:
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="35" name="AllTests">
<testsuite name="MathTest" tests="2" failures="1"* errors="0" time="15">
<testcase name="Addition" status="run" time="7" classname="">
<failure message="Value of: add(1, 1)
Actual: 3
Expected: 2" type=""/>
<failure message="Value of: add(1, -1)
Actual: 1
Expected: 0" type=""/>
</testcase>
<testcase name="Subtraction" status="run" time="5" classname="">
</testcase>
</testsuite>
<testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5">
<testcase name="NonContradiction" status="run" time="5" classname="">
</testcase>
</testsuite>
</testsuites>
要注意的事项:
- <testsuites>或<testsuite>元素的测试属性告诉多少测试功能,谷歌测试程序或测试用例包含,而失败属性告诉他们有多少失败。
- 时间属性表示测试、 测试用例或整个测试程序以毫秒为单位的持续时间。
- <failure>的每个元素对应于单个失败谷歌测试断言。
- JUnit 的一些概念不能应用于谷歌测试,然而我们必须符合 DTD。因此,您将看到一些虚拟元素和属性在报表中。您可以安全地忽略这些部件。
可用性:Linux、 Windows、 mac。
控制如何报告失败
断言失败变成破发点
当测试程序在调试器下的运行时,它都很方便,如果调试器可以捕获断言失败,并会自动放到交互模式。谷歌测试中断故障模式支持这种行为。
若要启用它, GTEST_BREAK_ON_FAILURE环境变量设置0以外的值。或者,您可以使用-gtest_break_on_failure命令行的标志。
可用性:Linux、 Windows、 mac。
禁用捕捉测试引发异常
可以使用谷歌测试带或不带例外启用。如果测试引发一个 c + + 异常或 (在 Windows) 结构化的异常 (SEH),默认情况下谷歌测试捕捉该异常,它会报告为测试失败,并继续下一个测试方法。这最大化测试运行的覆盖范围。此外,在 Windows 上未捕获的异常将导致一个弹出窗口,所以捕捉异常,可以自动运行的测试。
调试测试失败,但是,你会可以由调试器处理异常,这样您可以检查调用堆栈异常时引发。要做到这一点,将GTEST_CATCH_EXCEPTIONS环境变量设置为0,或使用-gtest_catch_exceptions = 0标志时运行测试。
可用性: Linux、 Windows、 mac。
让另一个测试框架的驱动器
如果您已经使用另一个测试框架并不准备完全切换到谷歌测试的项目工作,通过在您现有的测试中使用其说法可以多谷歌测试效益的获取。只需更改你看起来像的main ()函数:
#include "gtest/gtest.h"
int main(int argc, char** argv) {
::testing::GTEST_FLAG(throw_on_failure) = true;
// Important: Google Test must be initialized.
::testing::InitGoogleTest(&argc, argv);
... whatever your existing testing framework requires ...
}
这一点,您可以使用谷歌测试断言在本机断言的测试框架提供了,例如:
void TestFooDoesBar() {
Foo foo;
EXPECT_LE(foo.Bar(1), 100); // A Google Test assertion.
CPPUNIT_ASSERT(foo.IsEmpty()); // A native assertion.
}
如果谷歌测试断言失败时,它会打印错误消息并引发异常,将您的主机测试框架被视为失败。如果您禁用例外编译您的代码,失败的谷歌测试断言将转而退出程序与一个非零的代码,也将信号测试失败,您测试转轮。
如果你不写:: testing::GTEST_FLAG(throw_on_failure) = true ;在您main ()中,您可以或者启用此功能通过指定-gtest_throw_on_failure在命令行上的标志或GTEST_THROW_ON_FAILURE环境变量设置为非零值。
可用性:Linux、 Windows、 Mac ;自从 v1.3.0。
分发到多台机器测试功能
如果您有多台计算机,您可以使用来运行一个测试程序,您可能要并行运行的测试功能和更快的结果。我们要求尽可能此技术,每台机器称为陶.
谷歌测试是测试尽可能与兼容。要利用此功能,您测试转轮 (不是谷歌测试的一部分) 需要执行下列操作:
- 分配数量的机器 (碎片) 运行测试。
- 对每个陶、 GTEST_TOTAL_SHARDS环境变量设置的碎片的总数。它必须是相同的所有碎片。
- 对每个陶、 GTEST_SHARD_INDEX环境变量设置陶的索引。不同的碎片,必须指定不同的指标,必须在范围[0,GTEST_TOTAL_SHARDS-1].
- 在所有的碎片上运行相同的测试程序。当 Google 测试看到上面的两个环境变量时,它将选择要运行的测试功能的一个子集。跨所有碎片,将一次运行程序中的每个测试功能。
- 等待完成,然后收集和报告结果的所有碎片。
您的项目可能被写入不谷歌测试并因此不懂此协议测试。为了找出哪个测试支持尽可能您测试转轮,它可以设置环境变量GTEST_SHARD_STATUS_FILE为一个不存在的文件的路径。如果测试程序支持尽可能,它将创建此文件,以承认这一事实 (该文件的实际内容并不重要此时 ; 虽然我们可能会在未来在它坚持一些有用的信息。) ;否则,就不会创建它。
下面是一个示例,清楚。假设您有包含以下 5 测试函数测试程序foo_test :
TEST(A, V)
TEST(A, W)
TEST(B, X)
TEST(B, Y)
TEST(B, Z)
您可随时还有 3 台机。并行运行的测试功能,您会将GTEST_TOTAL_SHARDS设置为 3,在所有计算机上,并且设置GTEST_SHARD_INDEX为 0、 1 和 2 机器上分别。然后您将每个机器上运行相同的foo_test 。
谷歌测试有权更改工作如何分布碎片,但这里的一种可能情况:
- # 0 机运行A.V和b 十节.
- # 1 机运行A.W和B.Y.
- # 2 机运行B.Z.
可用性:Linux、 Windows、 Mac ;自从 1.3.0 版。
融合谷歌测试的源代码文件
谷歌测试实现包括 ~ 30 个文件 (不包括其自己的测试)。有时,您可能希望他们要打包在两个文件 ( .h和.cc) 相反,这样可以轻松地将它们复制到一台新机器和启动那里黑客攻击。为此我们提供实验 Python 脚本中的fuse_gtest_files.py 脚本 /目录 (自 1.3.0 版)。假定您使用 Python 2.4 或以上安装在您的机器上,只需转到该目录并运行
python fuse_gtest_files.py OUTPUT_DIR
您应该看到一个正在创建文件gtest/gtest.h和gtest/gtest-all.cc在它的OUTPUT_DIR目录。这些文件包含您要使用谷歌测试所需的一切。只是将它们复制到任意位置,您就可以编写测试。你可以使用生成文件脚本/测试中的文件为例对如何编译你对他们的测试。
从这里去哪里
恭喜 !您现在学会了更高级的谷歌测试工具,并已准备好解决更为复杂的测试任务。如果您想更深入了解,你可以阅读Frequently-Asked 的问题.