伤心客 发表于 2024-6-13 21:55:47

单元测试之CppTest测试框架

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.
其类图如下:
https://img-blog.csdnimg.cn/direct/3f417891cdaa4be291d64c65928548d8.png#pic_center
类界说如下:
class TestApp
{
    Test::Suite mainSuite_;
    TestApp();
public:
    static TestApp& Instance();

    voidaddSuite(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 <iostream>
#include <cstring>
#include <cstdio>

namespace
{
void usage()
{
    std::cout << "usage: test \n"
         << "where MODE may be one of:\n"
         << "--compiler\n"
         << "--html\n"
         << "--text-terse (default)\n"
         << "--text-verbose\n";
    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;
      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);
    }
    catch (...)
    {
      std::cout << "unexpected exception encountered\n";
      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() << '\n';
    }
    return 0;
}
主函数很简朴,不再详述。
4.2 测试用例

这里使用C++尺度库中std::mutex作为测试示例.
4.2.1 界说

#ifndef MUTEX_TEST_H
#define MUTEX_TEST_H
#include <cpptest/cpptest.h>

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 <thread>
#include <mutex>

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;
    for(int i = 0; i < 10; i++)
      threads = 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;
    for(int i = 0; i < 10; i++)
      threads = 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;
    for(int i = 0; i < 10; i++)
      threads = 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;
    for(int i = 0; i < 10; i++)
      threads = 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 说明测试报告按网页格式输出.

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 单元测试之CppTest测试框架