单元测试之CppTest测试框架

目录

  • 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.
其类图如下:
类图

类定义如下:

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

namespace
{
void usage()
{
    std::cout << "usage: test [MODE]\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[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\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[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 说明测试报告按网页格式输出.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/694911.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

App UI 风格,引领时尚

App UI 风格&#xff0c;引领时尚

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 6月9日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年6月9日 星期日 农历五月初四 1、 人社部&#xff1a;个人养老金开户人数已超6000万&#xff0c;其中31岁至40岁的中高收入人群是开户、缴费和购买产品的主力军。 2、 医保局刊文&#xff1a;研究显示集采仿制药替代原研药…

URL的编码解码(一),仅针对ASCII码字符

用十六进制对特定字符编码&#xff0c;利用百分号标识搜索字符串解码十六进制字符。 (笔记模板由python脚本于2024年06月09日 18:05:25创建&#xff0c;本篇笔记适合喜好探寻URL的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free…

内存管理--3.用幻灯片讲解C++手动内存管理

用幻灯片讲解C手动内存管理 1.栈内存的基本元素 2.栈内存的聚合对象 3.手动分配内存和释放内存 注意&#xff1a;手动分配内存&#xff0c;指的是在堆内存中。 除非实现自己的数据结构&#xff0c;否则永远不要手动分配内存! 即使这样&#xff0c;您也应该通过std::allocator…

如何在本地和远程删除 Git 分支

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;目前是武汉城市开发者社区主理人 擅长.net、C、python开发&#xff0c; 如果遇…

计算机组成原理之指令格式

1、指令的定义 零地址指令&#xff1a; 1、不需要操作数&#xff0c;如空操作、停机、关中断等指令。 2、堆栈计算机&#xff0c;两个操作数隐藏在栈顶和此栈顶&#xff0c;取两个操作数&#xff0c;并运算的结果后重新压回栈顶。 一地址指令&#xff1a; 二、三地址指令 四…

selenium-java自动化教程

文章目录 Selenium支持语言WebDriver 开始使用chromedriver模拟用户浏览访问模拟点击事件关闭弹窗&#xff0c;选中元素并点击 获取页面文本结语 Selenium Selenium是一个自动化测试工具&#xff0c;可以模拟用户操作web端浏览器的行为&#xff0c;包括点击、输入、选择等。也可…

高考后志愿填报信息采集系统制作指南

在高考的硝烟散去之后&#xff0c;每位学生都面临着一个重要的任务——志愿填报。老师们如何高效、准确地收集和整理这些信息&#xff0c;成为了一个棘手的问题。难道我们只能依赖传统的手工登记方式&#xff0c;忍受其繁琐和易错吗&#xff1f; 易查分是一个简单易用的在线工具…

数据结构--递归和数组

个人介绍 hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的…

ESP32:FreeRTOS节拍配置(vTaskDelay延时10ms改为1ms)

文章目录 背景方法手动修改sdkconfig通过idf.py menuconfig 背景 在FreeRTOS的默认配置中&#xff0c;任务调度的频率默认是100HZ&#xff0c;因此默认vTaskDelay默认延时是10ms。 FreeRTOS 的系统时钟节拍可以在配置文件 FreeRTOSConfig.h 里面设置&#xff1a;#define confi…

论文阅读KAN: Kolmogorov–Arnold Networks

学习了最近大热的KAN网络 论文地址&#xff1a;https://arxiv.org/pdf/2404.19756 按我个人读论文的习惯总结了如下几点&#xff1a; 1&#xff0c;背景&#xff1a; 1&#xff09;灵感来源&#xff1a;于Kolmogorov-Arnold表示定理&#xff0c;也就是多变量连续函数可以表…

技术与业务的完美融合:大数据BI如何真正提升业务价值

数据分析有一点经典案例 沃尔玛的啤酒和尿布案例 开始做BI的时候&#xff0c;大家肯定都看过书&#xff0c;那么一定也看过一个经典的案例&#xff0c;就是沃尔玛的啤酒和尿布的案例。这个案例确实很经典&#xff0c;但其实是一个失败的案例。为什么这么说呢&#xff1f;很明显…

html接口响应断言

接口响应值除类json格式&#xff0c;还有html格式 断言步骤 第一步&#xff1a;替换空格replace 原本返回的格式和网页内容一致&#xff0c;每行前面有很多空格&#xff0c;需要去除这些空格 第二步&#xff1a;分割split 因为行与行之前有回车符&#xff0c;所以把回车符替…

JAVA-LeetCode 热题 100 第56.合并区间

思路&#xff1a; class Solution {public int[][] merge(int[][] intervals) {if(intervals.length < 1) return intervals;List<int[]> res new ArrayList<>();Arrays.sort(intervals, (o1,o2) -> o1[0] - o2[0]);for(int[] interval : intervals){if(res…

cisco packet tracer 8.2.2 (思科模拟器) ospf路由协议

1 实验拓扑图 2 配置路由器和交换机 #sw1 en config t hostname sw1 ip routing int vlan 2 ip address 192.168.2.1 255.255.255.0 exit int vlan 3 ip address 192.168.3.1 255.255.255.0 exit int gigabitEthernet 1/0/1 switchport access vlan 2 exit int gigabitEthe…

在AMD GPU上加速大型语言模型的Flash Attention

Accelerating Large Language Models with Flash Attention on AMD GPUs — ROCm Blogs 引言 在这篇博客文章中&#xff0c;我们将指导您如何在AMD GPU上安装Flash Attention&#xff0c;并提供与在PyTorch中标准SDPA比较其性能的基准测试。我们还将测量Hugging Face中多个大型…

Facebook革新:数字社交的下一个阶段

在数字化时代&#xff0c;社交网络已经成为人们生活中不可或缺的一部分。作为全球最大的社交网络平台之一&#xff0c;Facebook一直在不断创新&#xff0c;引领着数字社交的发展。然而&#xff0c;随着科技的不断进步和社交需求的变化&#xff0c;Facebook正在走向一个新的阶段…

Linux下软件安装

提示&#xff1a;制作不易&#xff0c;可以点个关注和收藏哦。 前言 介绍 Ubuntu 下软件安装的几种方式&#xff0c;及 apt&#xff0c;dpkg 工具的使用。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考. 一、先体验一下 比如我们想安装一个软件&…

添加Microsoft.VisualStudio.TestTools.UnitTesting命名空间

创建“单元测试项目”&#xff0c;则自动添加 Microsoft.VisualStudio.TestTools.UnitTesting 命名空间

C语言:双链表

一、什么是双链表&#xff1f; 双链表&#xff0c;顾名思义&#xff0c;是一种每个节点都包含两个链接的链表&#xff1a;一个指向下一个节点&#xff0c;另一个指向前一个节点。这种结构使得双链表在遍历、插入和删除操作上都表现出色。与单链表相比&#xff0c;双链表不仅可以…