Google Test Sample09:定制化控制台输出_listener API 及 检查用例执行结果_reflection API v0.6
一、环境信息
- Visual Studio 2019
- Windows 10
二、Google Test Sample09
1. 示例概述
1.1 sample09演示了如何使用Google Test的两个API:listener 和 reflection
1.2 listener API可以用于实现控制台的定制化输出。这里的 console output就是指用例的执行结果窗体打印的信息(如下所示),按示例的方法可以进行定制化
1.3 reflection API可以检查测试用例的执行结果。sample09展示了如何在统计中剔除 预期结果触发Fail的用例,以便保障 注定失败的测试不会影响测试程序的结果
2. 目前的问题(原因已查明,待解决)
2.1 sample09目前可以编译并正常执行,但是代码中的两个预定目标均没有实现:(1) 定制控制台输出 (2) 剔除 预期结果是触发Fail的用例 。
–原因分析:需要带参数运行gtest(文中定义的是 --terse_output),但是在VS 2019默认条件下,不会带参数执行
2.2 示例9并没有讲解具体的单元测试、主要是gtest API的使用,因此个人决定先跳过遇到的问题,等实际用到了再说
2.3 示例9中撰写了 main()函数 int main(int argc, char** argv) {…} ,他为什么没有造成多main()函数的冲突:VS gtest工程自带main(),这个在后面也需要研究一下
3. sample09UnitTest.cpp
3.1 详细代码及个人注释如下
3.2 执行结果:并未实现定制化打印信息、预期触发Fail的用例也没有排除 ╮(╯▽╰)╭
#include "pch.h"
// This sample shows how to use Google Test listener API to implement an alternative console output
// and how to use the UnitTest reflection API to enumerate test cases and tests and to inspect their results.
// 示例展示了如何使用gtest监听接口去实现一个替换的控制台输出、如何使用gtest reflection接口去枚举测试用例和检查测试结果?
#include <stdio.h>
using ::testing::EmptyTestEventListener;
using ::testing::InitGoogleTest;
using ::testing::Test;
using ::testing::TestCase;
using ::testing::TestEventListeners; // TestEventListeners and EmptyTestEventListener
using ::testing::TestInfo; //TestInfo?
using ::testing::TestPartResult; //TestPartResult
using ::testing::UnitTest; //UnitTest?
namespace
{
//Provides alternative output mode which produces minimal amount of information about tests.
//提供可改变的输出模式,该模式生成最小数量的测试信息
class TersePrinter : public EmptyTestEventListener //Terse equal brief ,类TersePrinter是为定制化控制台输出而创建的
{
private:
// Called before any test activity starts. //任何测试活动启动前调用
void OnTestProgramStart(const UnitTest& /* unit_test */) override {} //此处没有任何信息输出
// Called after all test activities have ended. //所有测试结束后调用
void OnTestProgramEnd(const UnitTest &unit_test) override // 用到了引用。reference是i的引用 int i; int &reference = i;
{
fprintf(stdout, "TEST 123 456 789 %s\n", unit_test.Passed() ? "PASSED" : "FAILED");
fflush(stdout);
}
// Called before a test starts.//在一条测试用例开始前调用
void OnTestStart(const TestInfo& test_info) override
{
fprintf(stdout, "Test %s.%s starting\n", test_info.test_case_name(), test_info.name());
fflush(stdout);
}
// Called after a failed assertion or a SUCCEED() invocation. //在 一个失败的断言 或 SUCCEED()函数触发 后调用
void OnTestPartResult(const TestPartResult &test_part_result) override
{
fprintf(stdout,
"%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());
fflush(stdout);
}
// Called after a test ends.
void OnTestEnd(const TestInfo &test_info) override
{
fprintf(stdout, "Test %s.%s ending.\n",
test_info.test_case_name(),
test_info.name());
fflush(stdout);
}
}; // class TersePrinter 重新定义了控制台输出信息
TEST(CustomOutputTest, PrintsMessage) //通过宏TEST撰写的用例
{
printf("Printing something from the test body...\n");
}
TEST(CustomOutputTest, Succeeds)
{
SUCCEED() << "SUCCEED() has been invoked from here";
}
TEST(CustomOutputTest, Fails) //本条用例预期结果一定Fail,他用来配合gtest reflection接口定制化演示。 //但是实际未达成预定效果 原因不清楚
{
EXPECT_EQ(2, 3) << "This test fails in order to demonstrate alternative failure messages.";
}
} // namespace
int main(int argc, char** argv) // char** argv? argc,argv? //上面的类TersePrinter重新定义了控制台输出信息
{
InitGoogleTest(&argc, argv); //InitGoogleTest? &argc, argv?
bool terse_output = false; //terse mean brief
if (argc > 1 && strcmp(argv[1], "--terse_output") == 0)
terse_output = true; //strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数
else
printf("%s\n", "Run this program with --terse_output to change the way it prints its output.");
UnitTest &unit_test = *UnitTest::GetInstance(); //?
// If we are given the --terse_output command line flag, suppresses the standard output and attaches own result printer.
// 如果按自定义的输出格式打印测试结果,需要阻止gtest的标准输出并attach自定义的result printer
if (terse_output)
{
TestEventListeners &listeners = unit_test.listeners();
// Removes the default console output listener from the list so it will not receive events from Google Test and won't print any output.
// Since this operation transfers ownership of the listener to the caller we have to delete it as well.
// 从listeners列表中删除默认的控制台输出监听器
delete listeners.Release(listeners.default_result_printer());
// Adds the custom output listener to the list. It will now receive events from Google Test and print the alternative output.
// We don't have to worry about deleting it since Google Test assumes ownership over it after adding it to the list.
// 添加自定义的用例的输出信息 TersePrinter 到listeners列表,以便进行定制化输出打印。不需要考虑TersePrinter的释放
listeners.Append(new TersePrinter);
}
//上面就是gtest listener API的示例。listener接口可用于定制化控制台输出,以便打印定制化的用例执行信息
//下面是 gtest reflection接口使用演示:要达成一个什么样的目的,还不是很清楚
// -- reflection API : enumerate test cases and tests and to inspect their results
// reflection接口可以用于检查测试结果。但是目前不明确reflection接口包含哪些子类、函数
int ret_val = RUN_ALL_TESTS(); //RUN_ALL_TESTS()统计了测试用例条数吧?
// This is an example of using the UnitTest reflection API to inspect test results. Here we discount failures from the tests we expected to fail.
// 使用 gtest reflection接口检查测试结果。不理会测试中的失败用例 (这些用例的预期就是失败的) discount 不理会
int unexpectedly_failed_tests = 0; // unexpectedly_failed_tests 未预期失败的用例个数
//for循环应该是用来遍历所有用例的执行结果
for (int i = 0; i < unit_test.total_test_case_count(); ++i) //under VS2019,use total_test_case_count
{
const TestCase &test_suite = *unit_test.GetTestCase(i); //赋值操作 但用义不明? unit_test 对应测试用例集?
for (int j = 0; j < test_suite.total_test_count(); ++j)
{
const TestInfo &test_info = *test_suite.GetTestInfo(j);//赋值操作 但用义不明? test_suite对应单条测试用例?
// Counts failed tests that were not meant to fail (those without 'Fails' in the name).
// 统计执行失败的用例(不包括已知预期失败的用例 这些用例已打上了标签Fails)
if (test_info.result()->Failed() && strcmp(test_info.name(), "Fails") != 0) // TEST(CustomOutputTest, Fails){}
unexpectedly_failed_tests++;
}
}
// Test that were meant to fail should not affect the test program outcome.
// 注定失败的测试不应该影响测试程序的结果
if (unexpectedly_failed_tests == 0)
ret_val = 0;
return ret_val;
} //End