CppTest单元测试框架(更新)

news2024/11/19 9:40:29

目录

  • 1 背景
  • 2 设计
  • 3 实现
  • 4 使用
    • 4.1 主函数
    • 4.2 使用方法

1 背景

前面文章单元测试之CppTest测试框架中讲述利用宏ADD_SUITE将测试用例自动增加到测试框架中。但在使用中发现一个问题,就是通过宏ADD_SUITE增加多个测试Suite时,每次运行时都是所有测试Suite都运行,有的Suite运行比较慢,这对边写测试用例边编译运行时效率很低。于是就在原来测试框架下作出修改,即默认运行所有测试用例,不过可以通过命令指定测试用例来运行。

2 设计

修改后新的类图如下:
类图

修改说明:

  • TestApp 增加成员suites_,
  • addSuite增加参数name,表示测试Suite名字,该函数实现将suite增加到成员suites_中存起来。
  • run接口没变,实现时从suites_将suite增加到mainSuite_中,如果没指定测试用例则全部增加,否则只增加指定测试用例。
  • AutoAddSuite的构造函数增加参数用例名称。
  • 宏ADD_SUITE参数没变化,实现时将类型作为测试用例名称来注册

类定义如下:

#ifndef TESTAPP_H
#define TESTAPP_H
#include <cpptest/cpptest.h>
#include <map>
#include <memory>

class TestApp
{
    typedef std::map<std::string, std::unique_ptr<Test::Suite>> Suites;
    Test::Suite mainSuite_;
    Suites suites_;
    TestApp();
public:
    static TestApp& Instance();

    void  addSuite(const char* name, Test::Suite * suite);
    int run(int argc, char *argv[]);
};

#define theTestApp TestApp::Instance()

template<typename Suite>
struct AutoAddSuite
{
    AutoAddSuite(const char* Name) { theTestApp.addSuite(Name, new Suite()); }
};

#define ADD_SUITE(Type) AutoAddSuite<Type>  add##Type(#Type);

说明:

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

3 实现

#include "testapp.h"

#include <iostream>
#include <tuple>
#include <cstring>
#include <cstdio>

namespace
{
void usage()
{
    std::cout << "usage: test [MODE] [Suite]\n"
         << "where MODE may be one of:\n"
         << "  --compiler\n"
         << "  --html\n"
         << "  --text-terse (default)\n"
         << "  --text-verbose\n";
}

std::tuple<std::string, std::unique_ptr<Test::Output>>
cmdline(int argc, char* argv[])
{
    Test::Output* output = 0;
    std::string name;

    if (argc == 1)
        output = new Test::TextOutput(Test::TextOutput::Verbose);
    if(argc > 1)
    {
        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 if(strcmp(arg, "--help") == 0)
            std::tuple<std::string, std::unique_ptr<Test::Output>>("help", output);
        else
            std::cout << "invalid commandline argument: " << arg << std::endl;
    }
    if(argc > 2)
        name = argv[2];
    return std::tuple<std::string, std::unique_ptr<Test::Output>>(name, output);
}
}

TestApp & TestApp::Instance()
{
    static TestApp theApp;
    return theApp;
}

TestApp::TestApp()
{}

void TestApp::addSuite(const char* name, Test::Suite * suite)
{
    suites_.emplace(name, std::unique_ptr<Test::Suite>(suite));
}

int TestApp::run(int argc, char *argv[])
{
    try
    {
        auto params = cmdline(argc, argv);
        std::string name(std::move(std::get<0>(params)));
        std::unique_ptr<Test::Output> output(std::move(std::get<1>(params)));
        if(name == "help" || !output)
        {
            usage();
            std::cout << "where Suite may be one of(default - all):\n";
            for(auto & suite: suites_)
                std::cout << "  " << suite.first << "\n";
            return 0;
        }

        for(auto & suite: suites_)
        {
            if(name.empty())
                mainSuite_.add(std::move(suite.second));
            else if(name == suite.first)
            {
                mainSuite_.add(std::move(suite.second));
                break;
            }
        }
        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到suites_
  • run
    • 首先根据命令行返回Test::Output和要单独运行测试用例名称
    • 如果参数错误或help显示用法后退出主程序。
    • 遍历suites_,将suite添加到mainSuite_中(如果name不为空,则只添加名称为name的测试用例)
    • 然后调用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 使用方法

这里假定程序名称concurrent,显示用法:

 $ ./concurrent --help
usage: test [MODE] [Suite]
where MODE may be one of:
  --compiler
  --html
  --text-terse (default)
  --text-verbose
where Suite may be one of(default - all):
  AtomicSuite
  BlockQueueSuite
  ConditionVariableSuite
  FutureSuite
  LocksSuite
  MutexSuite
  RingQueueSuite
  ThreadSuite
  TimedMutexSuite

运行测试用例BlockQueueSuite:

$ ./concurrent --text-terse BlockQueueSuite
BlockQueueSuite: 0/2
I get a Apple pie
I get a Banana pie
I get a Pear pie
I get a Plum pie
I get a Pineapple pie

I get a Apple pie
I get a Banana pie
I get a Pear pie
I get a Plum pie
I get a Pineapple pie

I get a Apple
I get a Banana
I get a Pear
I get a Plum
I get a Pineapple
BlockQueueSuite: 1/2
I get a Apple pie in thread(3)

I get a Banana pie in thread(4)

I get a Pear pie in thread(0)

I get a Plum pie in thread(2)

I get a Pineapple pie in thread(1)

I get a Apple pie in thread(0)

I get a Banana pie in thread(2)

I get a Pear pie in thread(3)

I get a Plum pie in thread(1)

I get a Pineapple pie in thread(4)

I get a Apple in thread(1)

I get a Banana in thread(0)

I get a Pear in thread(2)

I get a Plum in thread(3)

I get a Pineapple in thread(4)
BlockQueueSuite: 2/2, 100% correct in 0.021808 seconds
Total: 2 tests, 100% correct in 0.021808 seconds

说明:

  • 如上所述只运行测试用例BlockQueueSuite

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内附下载方式 | 移远通信《5G RedCap技术发展及应用白皮书》重磅发布

6月25日&#xff0c;在2024 MWC上海前夕&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;正式发布其《5G RedCap技术发展及应用白皮书》。 该白皮书对RedCap的技术特点、市场趋势及应用场景进行了全面分析&#xff0c;基于5G技术的发展和演进&#xff…

Kafka入门-基础概念及参数

一、Kafka术语 Kafka属于分布式的消息引擎系统&#xff0c;它的主要功能是提供一套完备的消息发布与订阅解决方案。可以为每个业务、每个应用甚至是每类数据都创建专属的主题。 Kafka的服务器端由被称为Broker的服务进程构成&#xff0c;即一个Kafka集群由多个Broker组成&#…

一款开源、高颜值的AI物联网数据平台

介绍 AIOT人工智能物联网平台是一站式物联网开发基础平台&#xff0c;帮助企业快速实现数字化、精细化数据管理。核心系统为&#xff1a;物联网平台 数据中台&#xff08;数据底座&#xff09; AI。 同时支持文生图、语音合成等。大模型支持陆续也会慢慢开发。 物联系统介绍…

STM32存储左右互搏 模拟U盘桥接QSPI总线FATS读写FLASH W25QXX

STM32存储左右互搏 模拟U盘桥接QSPI总线FATS读写FLASH W25QXX STM32的USB接口可以模拟成为U盘&#xff0c;通过FATS文件系统对连接的存储单元进行U盘方式的读写。 这里介绍STM32CUBEIDE开发平台HAL库模拟U盘桥接Quad SPI总线FATS读写W25Q各型号FLASH的例程。 FLASH是常用的一种…

【学习】科大睿智解读ITSS通过后仍需关注和改进IT服务的原因

为了确保IT服务的质量和效率&#xff0c;很多企业拿到ITSS资质证书后&#xff0c;仍然需要持续关注和改进IT服务&#xff0c;科大睿智总结主要原因有以下几点&#xff1a; 1、随着企业发展业务和市场行情的变化&#xff0c;可能涉及到运维服务中新的业务流程、技术需求或者用户…

[深度学习] 门控循环单元GRU

门控循环单元&#xff08;Gated Recurrent Unit, GRU&#xff09;是一种用于处理序列数据的递归神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;变体&#xff0c;它通过引入门控机制来解决传统RNN在处理长序列时的梯度消失问题。GRU与长短期记忆网络&#xff0…

Arduino 旋转编码器

Arduino 旋转编码器 电位计 Arduino - Rotary Encoder In this tutorial, we are going to learn how to use the incremental encoder with Arduino. In detail, we will learn: 在本教程中&#xff0c;我们将学习如何将增量编码器与Arduino一起使用。详细来说&#xff0c;…

iptables(11)target(SNAT、DNAT、MASQUERADE、REDIRECT)

简介 前面我们已经介绍了ACCEPT、DROP、REJECT、LOG,这篇文章我们介绍SNAT、DNAT、MASQUERADE、REDIRECT,这几个参数的定义我们在上篇文章中都有介绍,我这里再列出回顾一下 DNAT(目标地址转换)和 SNAT(源地址转换) 原理:修改数据包的源或目标 IP 地址。通常用于 NAT(…

Maven高级理解属性

属性 在这一章节内容中&#xff0c;我们将学习两个内容&#xff0c;分别是 属性版本管理 属性中会继续解决分模块开发项目存在的问题&#xff0c;版本管理主要是认识下当前主流的版本定义方式。 4.1 属性 4.1.1 问题分析 讲解内容之前&#xff0c;我们还是先来分析问题: …

Games101 透视投影矩阵推导

目录 齐次坐标 透视投影 透视投影的四棱锥体挤压为正交投影的长方体 变换规定 转换过程 观察1 观察2 关于任意一点挤压后向哪里移动的问题&#xff0c;简单推导了一下 齐次坐标 如下&#xff0c;(x, y, z, 1) 表示空间中的xyz点&#xff0c;让它每个分量乘以k&#…

MySQL 基础概念

MySQL逻辑架构 MySQL 服务器逻辑架构图 最上层的服务并不是MySQL所独有的&#xff0c;大多数基于网络的客户端/服务器的工具或者服务都有类似的架构&#xff0c;比如连接管理、授权认证、安全等等。 大多数MySQL的核心服务都在第二层&#xff0c;包括查询解析、分析、优化、…

空间的维度

空间的维度----中科院科学智慧火花 当今世界科学前沿&#xff0c;最具有挑战性和最激动人心的理论&#xff0c;莫过于弦理论&#xff0c;他不仅仅融合了相对论和量子理论&#xff0c;甚至被认为是终极理论。弦理论最核心的内容就是多维空间。由于时间和空间概念必然要写进物理…

Echarts 图表添加点击事件跳转页面,但只有图表部分点击才会跳转页面,坐标轴,区域缩放等点击不跳转。

默认的点击事件是这样的&#xff1a; myChart.on(click, function (param) {console.log(param) }) 这个事件需要点击具体图形才会触发&#xff0c;例如我上面的图&#xff0c;想选择a柱子&#xff0c;就需要明确点击到柱体才行&#xff0c;明显不符合正常的预期&#xff0c;正…

FullCalendar日历组件集成实战(16)

背景 有一些应用系统或应用功能&#xff0c;如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件&#xff0c;但功能比较简单&#xff0c;用来做数据展现勉强可用。但如果需要进行复杂的数据展示&#xff0c;以及互动操作如通过点击添加事件&#xff0…

【Linux】Wmware Esxi磁盘扩容

目录 一、概述 1.1 磁盘分区概念 1.2 LVM概念 二、扩容步骤 二、报错 一、概述 1.1 磁盘分区概念 在 Linux 中&#xff0c;每一个硬件设备都映射到一个系统的文件&#xff0c;对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux把各种 IDE 设备分配了一个由 hd 前缀组成的文…

使用VBA隐藏图表中的系列

Excel中很多图表相关的操作&#xff0c;并不能通过录制宏得到代码&#xff0c;这个场景中&#xff0c;如下希望开发代码实现自动化&#xff0c;就会无从下手&#xff0c;其实只要找到相关的属性和方法&#xff0c;代码可能并不复杂。 Excel的线图如下所示&#xff0c;其中有三…

每日一学(面试考题)

1、ConCurrentHashMap为什么不允许key为null&#xff1f; 底层 putVal方法 中 如果key || value为空 抛出空指针异常 其实是为了避免在多线程并发场景下的歧义问题 在获取key 返回结果为null 无法判断是 put&#xff08;k&#xff0c;v&#xff09;的时候 value本身是n…

Python+Pytest+Allure+Yaml接口自动化测试框架详解

PythonPytestAllureYaml接口自动化测试框架详解 编撰人&#xff1a;CesareCheung 更新时间&#xff1a;2024.06.20 一、技术栈 PythonPytestAllureYaml 版本要求&#xff1a;Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 1、安装python3.7&#xff0c;并配置…

探索ONLYOFFICE桌面编辑器8.1:更强大的办公软件(新功能全新详解)

引入 时间到达2024年&#xff0c;办公软件已经成为不可或缺的的一部分。想到办公软件不知道大家首先想到那些产品 office 亦或是 WPS&#xff0c;但一个前者需要购买才能使用完整服务&#xff0c;一个漫天的弹广告不充会员什么都用不了。那难道世面上就没有一块正在好用无广告的…

一天跌20%,近500只下跌,低价可转债为何不香了?

6月以来&#xff0c;Wind可转债低价指数累计下跌7.3%&#xff0c;大幅跑输中价、高价转债。分析认为&#xff0c;市场调整的底层逻辑在于投资者对风险的重新评估和流动性的紧缩&#xff0c;宏观经济的波动和政策环境的不确定性、市场结构性的变化均对低价可转债市场产生了冲击。…