单元测试之CppTest测试框架

作者 : admin 本文共4450个字,预计阅读时间需要12分钟 发布时间: 2024-06-9 共3人阅读

目录

  • 1 背景
  • 2 设计
  • 3 实现
  • 4 使用
    • 4.1 主函数
    • 4.2 测试用例
      • 4.2.1 定义
      • 4.2.2 实现
    • 4.3 运行

1 背景

前面文章CppTest实战演示中讲述如何使用CppTest库。其主函数如下:

int main(int argc, char *argv[])
{
    Test::Suite mainSuite;
    Test::TextOutput output(Test::TextOutput::Verbose);

    mainSuite.add(std::unique_ptr<Test::Suite>(new SeesionSuite));
    mainSuite.run(output, true);

    return 0;
}

以上代码有一点不好,就是每增加一个测试Suite就需要在main函数中调用mainSuite.add增加用例。有没有办法测试Suite自动添加,不需要修改main函数。下面讲述的测试框架可以解决这个问题。

2 设计

首先设计类TestApp,该类是单例模式,可以添加测试Suite,其次AutoAddSuite是一模板类在其构造函数中自动添加测试Suite.
其类图如下:
单元测试之CppTest测试框架插图

类定义如下:

class TestApp
{
    Test::Suite mainSuite_;
    TestApp();
public:
    static TestApp& Instance();

    void  addSuite(Test::Suite * suite);
    int run(int argc, char *argv[]);
};
#define theTestApp TestApp::Instance()

template<typename Suite>
class AutoAddSuite
{
    Suite* suite;
public:
    AutoAddSuite()
    : suite(new Suite())
    { 
        theTestApp.addSuite(suite);
    }
};
#define ADD_SUITE(Type) AutoAddSuite<Type>  add##Type

说明:

  • TestApp类型是单例类,提高增加Suite接口和run接口
  • AutoAddSuite是一个自动添加Suite的模板类型
  • 宏ADD_SUITE定义了AutoAddSuite对象,用于自动添加。

3 实现

#include "testapp.h"
#include 
#include 
#include 
namespace
{
void usage()
{
std::cout << "usage: test [MODE]
"
<< "where MODE may be one of:
"
<< "  --compiler
"
<< "  --html
"
<< "  --text-terse (default)
"
<< "  --text-verbose
";
exit(0);
}
std::unique_ptr<Test::Output> cmdline(int argc, char* argv[])
{
if (argc > 2)
usage(); // will not return
Test::Output* output = 0;
if (argc == 1)
output = new Test::TextOutput(Test::TextOutput::Verbose);
else
{
const char* arg = argv[1];
if (strcmp(arg, "--compiler") == 0)
output = new Test::CompilerOutput;
else if (strcmp(arg, "--html") == 0)
output =  new Test::HtmlOutput;
else if (strcmp(arg, "--text-terse") == 0)
output = new Test::TextOutput(Test::TextOutput::Terse);
else if (strcmp(arg, "--text-verbose") == 0)
output = new Test::TextOutput(Test::TextOutput::Verbose);
else
{
std::cout << "invalid commandline argument: " << arg << std::endl;
usage(); // will not return
}
}
return std::unique_ptr<Test::Output>(output);
}
}
TestApp & TestApp::Instance()
{
static TestApp theApp;
return theApp;
}
TestApp::TestApp()
{}
void TestApp::addSuite(Test::Suite * suite)
{
mainSuite_.add(std::unique_ptr<Test::Suite>(suite));
}
int TestApp::run(int argc, char *argv[])
{
try
{
std::unique_ptr<Test::Output> output(cmdline(argc, argv));
mainSuite_.run(*output, true);
Test::HtmlOutput* const html = dynamic_cast<Test::HtmlOutput*>(output.get());
if (html)
html->generate(std::cout, true, argv[0]);
}
catch (...)
{
std::cout << "unexpected exception encountered
";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

说明:

  • Instance 返回一个单例引用
  • addSuite 增加Suite到mainSuite_
  • run
    • 首先根据命令行返回Test::Output
    • 然后调用mainSuite_运行测试用例
    • 最后如果类型是Output是Test::HtmlOutput类型,则将结果输出到标准输出std::cout.

4 使用

4.1 主函数

#include "testapp.h"
int main(int argc, char *argv[])
{
try
{
theTestApp.run(argc, argv);
}
catch(const std::exception& e)
{
std::cerr << e.what() << '
';
}
return 0;
}

主函数很简单,不再详述。

4.2 测试用例

这里使用C++标准库中std::mutex作为测试示例.

4.2.1 定义

#ifndef MUTEX_TEST_H
#define MUTEX_TEST_H
#include 
class MutexSuite : public Test::Suite
{
public:
MutexSuite()
{
TEST_ADD(MutexSuite::construct)
TEST_ADD(MutexSuite::lock)
TEST_ADD(MutexSuite::try_lock)
TEST_ADD(MutexSuite::unlock)
}
void construct();
void lock();
void try_lock();
void unlock();
};
#endif

说明:

  • cpptest库标准使用,不再详述。

4.2.2 实现

#include "mutex_test.h"
#include "testapp.h"
#include 
#include 
ADD_SUITE(MutexSuite);
void addCount(std::mutex & mutex, int & count)
{
mutex.lock();
count++;
mutex.unlock();
}
void MutexSuite::construct()
{
std::mutex muxtex;
int count = 0;
std::thread threads[10];
for(int i = 0; i < 10; i++)
threads[i] = std::thread(addCount, std::ref(muxtex), std::ref(count));
for(auto &thread : threads)
thread.join();
TEST_ASSERT_EQUALS(10, count)   
}
void MutexSuite::lock()
{
std::mutex muxtex;
int count = 10;
std::thread threads[10];
for(int i = 0; i < 10; i++)
threads[i] = std::thread(addCount, std::ref(muxtex), std::ref(count));
for(auto &thread : threads)
thread.join();
TEST_ASSERT_EQUALS(20, count)   
}
struct Function
{
volatile int counter = 0;
void add_10k_count(std::mutex & muxtex)
{
for(int i = 0; i < 10000; i++)
{
if(muxtex.try_lock())
{
++counter;
muxtex.unlock();
}
}
}
};
void MutexSuite::try_lock()
{
std::mutex muxtex;
Function function;
std::thread threads[10];
for(int i = 0; i < 10; i++)
threads[i] = std::thread(&Function::add_10k_count, std::ref(function), std::ref(muxtex));
for(auto &thread : threads)
thread.join();
TEST_ASSERT_EQUALS(true, function.counter < (10 * 10000))
std::cerr << "function.counter: " << function.counter << std::endl;
}
void MutexSuite::unlock()
{
std::mutex muxtex;
int count = 20;
std::thread threads[10];
for(int i = 0; i < 10; i++)
threads[i] = std::thread(addCount, std::ref(muxtex), std::ref(count));
for(auto &thread : threads)
thread.join();
TEST_ASSERT_EQUALS(30, count)   
}

说明:

  • 重点说明下文件头部宏ADD_SUITE的使用,如下所示传递给ADD_SUITE的参数正是MutexSuite,通过该定义,将MutexSuite自动添加到TestApp实例中,不需要修改main函数.
ADD_SUITE(MutexSuite);

4.3 运行

$ testapp --html

说明:

  • testapp是编译出的可执行文件
  • 参数–html 说明测试报告按网页格式输出.
本站无任何商业行为
个人在线分享 » 单元测试之CppTest测试框架
E-->