单元测试之CppTest测试框架

打印 上一主题 下一主题

主题 666|帖子 666|积分 1998

1 背景

前面文章CppTest实战演示中报告如何使用CppTest库。其主函数如下:
  1. int main(int argc, char *argv[])
  2. {
  3.     Test::Suite mainSuite;
  4.     Test::TextOutput output(Test::TextOutput::Verbose);
  5.     mainSuite.add(std::unique_ptr<Test::Suite>(new SeesionSuite));
  6.     mainSuite.run(output, true);
  7.     return 0;
  8. }
复制代码
以上代码有一点不好,就是每增加一个测试Suite就必要在main函数中调用mainSuite.add增加用例。有没有办法测试Suite自动添加,不必要修改main函数。下面报告的测试框架可以办理这个问题。
2 设计

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

类界说如下:
  1. class TestApp
  2. {
  3.     Test::Suite mainSuite_;
  4.     TestApp();
  5. public:
  6.     static TestApp& Instance();
  7.     void  addSuite(Test::Suite * suite);
  8.     int run(int argc, char *argv[]);
  9. };
  10. #define theTestApp TestApp::Instance()
  11. template<typename Suite>
  12. class AutoAddSuite
  13. {
  14.     Suite* suite;
  15. public:
  16.     AutoAddSuite()
  17.     : suite(new Suite())
  18.     {
  19.         theTestApp.addSuite(suite);
  20.     }
  21. };
  22. #define ADD_SUITE(Type) AutoAddSuite<Type>  add##Type
复制代码
说明:


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

  1. #include "testapp.h"
  2. #include <iostream>
  3. #include <cstring>
  4. #include <cstdio>
  5. namespace
  6. {
  7. void usage()
  8. {
  9.     std::cout << "usage: test [MODE]\n"
  10.          << "where MODE may be one of:\n"
  11.          << "  --compiler\n"
  12.          << "  --html\n"
  13.          << "  --text-terse (default)\n"
  14.          << "  --text-verbose\n";
  15.     exit(0);
  16. }
  17. std::unique_ptr<Test::Output> cmdline(int argc, char* argv[])
  18. {
  19.     if (argc > 2)
  20.         usage(); // will not return
  21.     Test::Output* output = 0;
  22.     if (argc == 1)
  23.         output = new Test::TextOutput(Test::TextOutput::Verbose);
  24.     else
  25.     {
  26.         const char* arg = argv[1];
  27.         if (strcmp(arg, "--compiler") == 0)
  28.             output = new Test::CompilerOutput;
  29.         else if (strcmp(arg, "--html") == 0)
  30.             output =  new Test::HtmlOutput;
  31.         else if (strcmp(arg, "--text-terse") == 0)
  32.             output = new Test::TextOutput(Test::TextOutput::Terse);
  33.         else if (strcmp(arg, "--text-verbose") == 0)
  34.             output = new Test::TextOutput(Test::TextOutput::Verbose);
  35.         else
  36.         {
  37.             std::cout << "invalid commandline argument: " << arg << std::endl;
  38.             usage(); // will not return
  39.         }
  40.     }
  41.     return std::unique_ptr<Test::Output>(output);
  42. }
  43. }
  44. TestApp & TestApp::Instance()
  45. {
  46.     static TestApp theApp;
  47.     return theApp;
  48. }
  49. TestApp::TestApp()
  50. {}
  51. void TestApp::addSuite(Test::Suite * suite)
  52. {
  53.     mainSuite_.add(std::unique_ptr<Test::Suite>(suite));
  54. }
  55. int TestApp::run(int argc, char *argv[])
  56. {
  57.     try
  58.     {
  59.         std::unique_ptr<Test::Output> output(cmdline(argc, argv));
  60.         mainSuite_.run(*output, true);
  61.         Test::HtmlOutput* const html = dynamic_cast<Test::HtmlOutput*>(output.get());
  62.         if (html)
  63.             html->generate(std::cout, true, argv[0]);
  64.     }
  65.     catch (...)
  66.     {
  67.         std::cout << "unexpected exception encountered\n";
  68.         return EXIT_FAILURE;
  69.     }
  70.     return EXIT_SUCCESS;
  71. }
复制代码
说明:


  • Instance 返回一个单例引用
  • addSuite 增加Suite到mainSuite_
  • run

    • 起首根据命令行返回Test::Output
    • 然后调用mainSuite_运行测试用例
    • 最后如果类型是Output是Test::HtmlOutput类型,则将结果输出到尺度输出std::cout.

4 使用

4.1 主函数

  1. #include "testapp.h"
  2. int main(int argc, char *argv[])
  3. {
  4.     try
  5.     {
  6.         theTestApp.run(argc, argv);
  7.     }
  8.     catch(const std::exception& e)
  9.     {
  10.         std::cerr << e.what() << '\n';
  11.     }
  12.     return 0;
  13. }
复制代码
主函数很简朴,不再详述。
4.2 测试用例

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

  1. #ifndef MUTEX_TEST_H
  2. #define MUTEX_TEST_H
  3. #include <cpptest/cpptest.h>
  4. class MutexSuite : public Test::Suite
  5. {
  6. public:
  7.     MutexSuite()
  8.     {
  9.         TEST_ADD(MutexSuite::construct)
  10.         TEST_ADD(MutexSuite::lock)
  11.         TEST_ADD(MutexSuite::try_lock)
  12.         TEST_ADD(MutexSuite::unlock)
  13.     }
  14.     void construct();
  15.     void lock();
  16.     void try_lock();
  17.     void unlock();
  18. };
  19. #endif
复制代码
说明:


  • cpptest库尺度使用,不再详述。
4.2.2 实现

  1. #include "mutex_test.h"
  2. #include "testapp.h"
  3. #include <thread>
  4. #include <mutex>
  5. ADD_SUITE(MutexSuite);
  6. void addCount(std::mutex & mutex, int & count)
  7. {
  8.     mutex.lock();
  9.     count++;
  10.     mutex.unlock();
  11. }
  12. void MutexSuite::construct()
  13. {
  14.     std::mutex muxtex;
  15.     int count = 0;
  16.     std::thread threads[10];
  17.     for(int i = 0; i < 10; i++)
  18.         threads[i] = std::thread(addCount, std::ref(muxtex), std::ref(count));
  19.     for(auto &thread : threads)
  20.         thread.join();
  21.     TEST_ASSERT_EQUALS(10, count)   
  22. }
  23. void MutexSuite::lock()
  24. {
  25.     std::mutex muxtex;
  26.     int count = 10;
  27.     std::thread threads[10];
  28.     for(int i = 0; i < 10; i++)
  29.         threads[i] = std::thread(addCount, std::ref(muxtex), std::ref(count));
  30.     for(auto &thread : threads)
  31.         thread.join();
  32.     TEST_ASSERT_EQUALS(20, count)   
  33. }
  34. struct Function
  35. {
  36.     volatile int counter = 0;
  37.     void add_10k_count(std::mutex & muxtex)
  38.     {
  39.         for(int i = 0; i < 10000; i++)
  40.         {
  41.             if(muxtex.try_lock())
  42.             {
  43.                 ++counter;
  44.                 muxtex.unlock();
  45.             }
  46.         }
  47.     }
  48. };
  49. void MutexSuite::try_lock()
  50. {
  51.     std::mutex muxtex;
  52.     Function function;
  53.     std::thread threads[10];
  54.     for(int i = 0; i < 10; i++)
  55.         threads[i] = std::thread(&Function::add_10k_count, std::ref(function), std::ref(muxtex));
  56.     for(auto &thread : threads)
  57.         thread.join();
  58.     TEST_ASSERT_EQUALS(true, function.counter < (10 * 10000))
  59.     std::cerr << "function.counter: " << function.counter << std::endl;
  60. }
  61. void MutexSuite::unlock()
  62. {
  63.     std::mutex muxtex;
  64.     int count = 20;
  65.     std::thread threads[10];
  66.     for(int i = 0; i < 10; i++)
  67.         threads[i] = std::thread(addCount, std::ref(muxtex), std::ref(count));
  68.     for(auto &thread : threads)
  69.         thread.join();
  70.     TEST_ASSERT_EQUALS(30, count)   
  71. }
复制代码
说明:


  • 重点说明下文件头部宏ADD_SUITE的使用,如下所示转达给ADD_SUITE的参数正是MutexSuite,通过该界说,将MutexSuite自动添加到TestApp实例中,不必要修改main函数.
  1. ADD_SUITE(MutexSuite);
复制代码
4.3 运行

  1. $ testapp --html
复制代码
说明:


  • testapp是编译出的可实行文件
  • 参数–html 说明测试报告按网页格式输出.

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表