Unity(单元测试)在STM32上的移植与应用

news2024/11/26 21:20:14

概述

Unity Test是一个为C构建的单元测试框架。本文基于STM32F407为基础,完全使用STM32CubeIDE进行开发,移植和简单使用Unity。

单片机型号:STM32F407VET6

软件:STM32CubeIDE  Version: 1.14.1    Unity Version:2.6.0

一、配置stm32工程

新建工程,选择407芯片,生成工程后开始配置硬件,这里我们只使用了串口1,作为打印输出串口,按照图片设置,波特率等根据需要设置,这里我使用的默认值。

我习惯单独生成c和h文件。

保存生成代码。

在main.c文件中添加串口重定向函数

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int __io_putchar(int ch)
{
    /* Implementation of __io_putchar */
	/* e.g. write a character to the UART1 and Loop until the end of transmission */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFFFFFF);

    return ch;
}
int __io_getchar(void)
{
  /* Implementation of __io_getchar */
    char rxChar;

    // This loops in case of HAL timeout, but if an ok or error occurs, we continue
    while (HAL_UART_Receive(&huart1, (uint8_t *)&rxChar, 1, 0xFFFFFFFF) == HAL_TIMEOUT);

    return rxChar;
}
/* USER CODE END 0 */

此时理论上可以编译通过,并且printf好用。

二、下载unity源码

GitHub - ThrowTheSwitch/Unity: Simple Unit Testing for C

源码地址如上。

在工程根路径下创建Unity文件夹,并将unity源码中的src文件夹中的文件放到这个目录中。并将example文件夹中的unity_config.h也放到目录中。

在工程中右键并刷新

这时就会看到我们添加的文件夹了。

在工程上右键Properties,如下图步骤添加unity到includes目录中。

如上图,添加源文件到工程中参与编译。

此时就可以编译了,可以正常编译通过。

这里说一下配置文件,unity_config.h,如果使用的是stm32的cube,那么这个文件什么都不用写,如果使用的是其他mcu或者编译器,需要详细阅读并进行相关的宏定义。

三、测试程序

下面我先简单翻译一下github上的readme。

基本有效性测试

TEST_ASSERT_TRUE(condition)
如果条件结果为 false,则失败
TEST_ASSERT_FALSE(condition)
如果条件结果为 true,则失败
TEST_ASSERT(condition)
另一种方式TEST_ASSERT_TRUE
TEST_ASSERT_UNLESS(condition)
另一种方式TEST_ASSERT_FALSE
TEST_FAIL()
TEST_FAIL_MESSAGE(message)
此测试会自动标记为失败。 输出消息,说明原因。

数值断言:整数

TEST_ASSERT_EQUAL_INT(expected, actual)
TEST_ASSERT_EQUAL_INT8(expected, actual)
TEST_ASSERT_EQUAL_INT16(expected, actual)
TEST_ASSERT_EQUAL_INT32(expected, actual)
TEST_ASSERT_EQUAL_INT64(expected, actual)
比较两个整数是否相等,并将错误显示为有符号整数。 将根据您的自然整数大小执行强制转换, 当您需要指定确切的大小时,您可以使用特定版本。
TEST_ASSERT_EQUAL_UINT(expected, actual)
TEST_ASSERT_EQUAL_UINT8(expected, actual)
TEST_ASSERT_EQUAL_UINT16(expected, actual)
TEST_ASSERT_EQUAL_UINT32(expected, actual)
TEST_ASSERT_EQUAL_UINT64(expected, actual)
比较两个整数是否相等,并将错误显示为无符号整数。 与 INT 一样,也有不同大小的变体。
TEST_ASSERT_EQUAL_HEX(expected, actual)
TEST_ASSERT_EQUAL_HEX8(expected, actual)
TEST_ASSERT_EQUAL_HEX16(expected, actual)
TEST_ASSERT_EQUAL_HEX32(expected, actual)
TEST_ASSERT_EQUAL_HEX64(expected, actual)
比较两个整数是否相等,并将错误显示为十六进制。与其他整数比较一样,您可以指定大小。。。这里的大小也将影响所示出的半字节的数量(例如,将示出4个半字节)。
TEST_ASSERT_EQUAL(expected, actual)
另一种TEST_ASSERT_EQUAL_INT的方式
TEST_ASSERT_INT_WITHIN(delta, expected, actual)
断言实际值在预期值的正负增量范围内。 这也具有特定尺寸的变体。
TEST_ASSERT_GREATER_THAN(threshold, actual)
断言实际值大于阈值。 这也具有特定尺寸的变体。
TEST_ASSERT_LESS_THAN(threshold, actual)
断言实际值小于阈值。 这也具有特定尺寸的变体。

数 组

_ARRAY
您可以附加到这些宏中的任何一个,以进行该类型的数组比较。在这里,您需要更加关心被检查值的实际大小。您还将指定一个额外的参数,即要比较的元素数。例如:_ARRAY
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, elements)
_EACH_EQUAL
另一个数组比较选项是检查数组的每个元素是否等于单个期望值。 为此,请指定 EACH_EQUAL 宏。 例如:
TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, elements)

数值断言:按位

TEST_ASSERT_BITS(mask, expected, actual)
使用整数掩码指定应在另外两个整数之间比较哪些位。 比较掩码中的高位,忽略低位。

TEST_ASSERT_BITS_HIGH(mask, actual)
使用整数掩码指定应检查哪些位以确定它们是否全部设置为高电平。 比较掩码中的高位,忽略低位。

TEST_ASSERT_BITS_LOW(mask, actual)
使用整数掩码指定应检查哪些位以确定它们是否全部设置为低电平。 比较掩码中的高位,忽略低位。

TEST_ASSERT_BIT_HIGH(bit, actual)
测试单个位并验证它是否为高电平。 对于 32 位整数,该位指定为 0-31。

TEST_ASSERT_BIT_LOW(bit, actual)
测试单个位并验证它是否为低电平。 对于 32 位整数,该位指定为 0-31。

数值断言:浮点数

TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)
TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual)
断言实际值在预期值的正负增量范围内。

TEST_ASSERT_FLOAT_NOT_WITHIN(delta, expected, actual)
TEST_ASSERT_DOUBLE_NOT_WITHIN(delta, expected, actual)
断言实际值不在预期值的正负增量范围内。

TEST_ASSERT_EQUAL_FLOAT(expected, actual)
TEST_ASSERT_EQUAL_DOUBLE(expected, actual)
断言两个浮点值在预期值的一小部分 % 增量内“相等”。

TEST_ASSERT_NOT_EQUAL_FLOAT(expected, actual)
TEST_ASSERT_NOT_EQUAL_DOUBLE(expected, actual)
断言两个浮点值在期望值的一小部分 % 增量内不“相等”。

TEST_ASSERT_LESS_THAN_FLOAT(threshold, actual)
TEST_ASSERT_LESS_THAN_DOUBLE(threshold, actual)
TEST_ASSERT_GREATER_THAN_FLOAT(threshold, actual)
TEST_ASSERT_GREATER_THAN_DOUBLE(threshold, actual)
断言实际值小于或大于阈值。

也有和变化。 它们遵循与以下相同的平等规则: 如果这两个值在预期值的一小部分 % 增量范围内,则断言将通过。LESS_OR_EQUALGREATER_OR_EQUALTEST_ASSERT_EQUAL_FLOATTEST_ASSERT_EQUAL_DOUBLE

字符串断言

TEST_ASSERT_EQUAL_STRING(expected, actual)
比较两个以 null 结尾的字符串。 如果任何字符不同或长度不同,则失败。

TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len)
比较两个字符串。 如果任何字符不同,则失败,在 len 字符之后停止比较。

TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message)
比较两个以 null 结尾的字符串。 如果任何字符不同或长度不同,则失败。 失败时输出自定义消息。

TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message)
比较两个字符串。 如果任何字符不同,则失败,在 len 字符之后停止比较。 失败时输出自定义消息。

指针断言

大多数指针操作只需使用上面的整数比较即可执行。 但是,为了清楚起见,添加了几个特殊情况。

TEST_ASSERT_NULL(pointer)
如果指针不等于 NULL 则失败

TEST_ASSERT_NOT_NULL(pointer)
如果指针等于 NULL 则失败

内存断言

TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)
比较两个内存块。 对于不能被强制执行为标准类型的类型来说,这是一个很好的通用断言...... 但是,由于它是内存比较,因此您必须小心数据类型被封装。

我们在工程Unity文件夹中创建test_unity.c文件,用于填写unity测试程序,我们先定义测试函数

/*
 * test_unity.c
 *
 *  Created on: Feb 14, 2024
 *      Author: Administrator
 */

#include "unity.h"


void test_unity(void)
{

}

并且将void test_unity(void)函数添加到main.h中

/* USER CODE BEGIN EFP */
void test_unity(void);
/* USER CODE END EFP */

然后在main.c中调用 test_unity函数。

  /* USER CODE BEGIN 2 */
  test_unity();
  /* USER CODE END 2 */

这时候编译是可以通过的。

我们接下来开始编写测试函数。

/*
 * test_unity.c
 *
 *  Created on: Feb 14, 2024
 *      Author: Administrator
 */

#include "unity.h"
#include <stdio.h>
#include <stdbool.h>

bool IsTrue(bool in)
{
	return in;
}


void testFunc(void)
{
	TEST_ASSERT_TRUE(IsTrue(true));
	TEST_ASSERT_TRUE(IsTrue(false));
}

void test_unity(void)
{
	printf("\r\n*****hello unity*******\r\n");
	RUN_TEST(testFunc);
	UNITY_END();
}

这个时候再编译就会报错

因为我们有两个函数未实现,

/*
 * test_unity.c
 *
 *  Created on: Feb 14, 2024
 *      Author: Administrator
 */

#include "unity.h"
#include <stdio.h>
#include <stdbool.h>

void setUp(void)
{
}

void tearDown(void)
{
}

bool IsTrue(bool in)
{
	return in;
}


void testFunc(void)
{
	TEST_ASSERT_TRUE(IsTrue(true));
	TEST_ASSERT_TRUE(IsTrue(false));
}

void test_unity(void)
{
	printf("\r\n*****hello unity*******\r\n");
	RUN_TEST(testFunc);
	UNITY_END();
}

这时候我们就可以编译过了。

用例的初始化:setUp()
用例的释放:tearDown()
这俩分别是在每个case之前和之后都会运行一次。
setUp() 方法用于用例的初始化,比如在执行测试用例之前进行的变量定义、初始化等。
tearDown() 方法则用于用例的释放,比如测试后的清理工作,比如数据还原、资源释放等。

运行输出如下:

符合预期,我们再写几个,完善一下测试程序。

/*
 * test_unity.c
 *
 *  Created on: Feb 14, 2024
 *      Author: Administrator
 */

#include "unity.h"
#include <stdio.h>
#include <stdbool.h>

void setUp(void)
{
}

void tearDown(void)
{
}

bool IsTrue(bool in)
{
	return in;
}


void testBoolPassFunc(void)
{
	TEST_ASSERT_TRUE(IsTrue(true));
}

void testBoolFailFunc(void)
{
	TEST_ASSERT_TRUE(IsTrue(false));
}

void testIntFunc(void)
{
	TEST_ASSERT_EQUAL_INT(1,1);
	uint8_t v = 10;
	TEST_ASSERT_EQUAL_INT(10, v);
}

void testArrayPassFunc(void)
{
	uint8_t a[3] = {1,2,3};
	uint8_t b[3] = {1,2,3};
	TEST_ASSERT_EQUAL_HEX8_ARRAY(a, b, 3);
}

void testArrayFailFunc(void)
{
	uint8_t a[3] = {1,2,3};
	uint8_t b[3] = {1,2,4};
	TEST_ASSERT_EQUAL_HEX8_ARRAY(a, b, 3);
}

void testBitsFunc(void)
{
	TEST_ASSERT_BITS(0xF0, 0x35, 0x34);
}

void testFloatPassFunc(void)
{
	// 这些断言验证actual参数处于expected参数的+/-delta之间。
	TEST_ASSERT_FLOAT_WITHIN(0.4, 1.2, 1.5);
}

void testFloatFailFunc(void)
{
	// 这些断言验证actual参数处于expected参数的+/-delta之间。
	TEST_ASSERT_FLOAT_WITHIN(0.2, 1.2, 1.5);
}

void testStringFunc(void)
{
	char *s = "hello unity";
	TEST_ASSERT_EQUAL_STRING(s, "hello unity");
}

void testStringMessageFunc(void)
{
	char *s = "hello unity";
	TEST_ASSERT_EQUAL_STRING_MESSAGE(s, "hello unity!", "I'm a message!");
}

void test_unity(void)
{
	printf("\r\n*****hello unity*******\r\n");
	RUN_TEST(testBoolPassFunc);
	RUN_TEST(testBoolFailFunc);
	RUN_TEST(testIntFunc);
	RUN_TEST(testArrayPassFunc);
	RUN_TEST(testArrayFailFunc);
	RUN_TEST(testBitsFunc);
	RUN_TEST(testFloatPassFunc);
	RUN_TEST(testFloatFailFunc);
	RUN_TEST(testStringFunc);
	RUN_TEST(testStringMessageFunc);
	UNITY_END();
}

当我们把失败的case都去掉后。

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

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

相关文章

【报错解决】-bash: export: `-8‘: not a valid identifier 不是有效的标识符

现象 一登陆就提示-bash: export: -8’: not a valid identifier 不是有效的标识符 问题出现的原因 设置字符集时多写了空格 [rootdb1 ~]# cat >>/etc/profile<<EOF export LANGen_US.UTF -8(-8前不应有空格) EOF 解决方法 cd /etc vi profile 把export带有-8的…

第17讲我参与的投票列表实现

我参与的投票列表实现 sql: SELECT * FROM t_vote WHERE id IN (SELECT vote_id FROM t_vote_detail WHERE openido30ur5JpAsAUyGBkR0uW4IxvahR8)/*** 获取指定用户参与的投票* param token* return*/ RequestMapping("/listOfJoinUser") public R listOfJoinUser(R…

Hive的相关概念——分区表、分桶表

目录 一、Hive分区表 1.1 分区表的概念 1.2 分区表的创建 1.3 分区表数据加载及查询 1.3.1 静态分区 1.3.2 动态分区 1.4 分区表的本质及使用 1.5 分区表的注意事项 1.6 多重分区表 二、Hive分桶表 2.1 分桶表的概念 2.2 分桶表的创建 2.3 分桶表的数据加载 2.4 …

电脑上用什么软件恢复数据?2024年受欢迎的恢复软件推荐

在当今数字化的时代&#xff0c;电脑已经成为我们生活中不可或缺的工具。然而&#xff0c;由于各种原因&#xff0c;我们的电脑可能会出现数据丢失的情况。这时&#xff0c;一款好的数据恢复软件就显得尤为重要。本文将为大家介绍一款在2024年备受推崇的数据恢复软件&#xff0…

react渲染流程是怎样的

整体流程&#xff1a; react的核心可以用uifn(state)来表示&#xff0c;更详细可以用&#xff1a; const state reconcile(update); const UI commit(state);上面的fn可以分为如下一个部分&#xff1a; Scheduler&#xff08;调度器&#xff09;&#xff1a; 调度任务&…

Android adb使用超级大全

Android adb使用超级大全 ADB&#xff0c;即Android Debug Bridge&#xff0c;是一款强大的工具&#xff0c;对于Android开发/测试人员来说是不可或缺的&#xff0c;同时也是Android设备玩家的好玩具。本文将详细介绍ADB的使用方法。 ADB的基本用法如下&#xff1a; 命令语法…

Virt a Mate(VAM)游戏折腾记录

如有更新见原文&#xff1a;https://blog.iyatt.com/?p13283 1 前言 如果在网上看到有些视频名字带有 VAM 的&#xff0c;可能就是玩这个游戏录屏的。这个游戏可以建模、操作模型动作、构建场景等等。之前大致知道有这么个东西&#xff0c;只是电脑配置太差了&#xff0c;新…

java数据结构与算法刷题-----LeetCode459. 重复的子字符串

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 本题的高效解法&#xff0c;需要使用KMP算法中&#xff0c;NEXT数组的处理…

【机器学习案例3】从科学论文图片中提取标题、作者和摘要【含源码】

在这个项目中,我的目标是从科学论文图片中提取某些部分(标题、作者和摘要)。预期提取部分是科学论文中常见的部分,例如标题、摘要和作者。输入与最终结果。我的输入是将第一页纸转换成图像。最终结果是一个 txt 文件,其中包含标题、作者和摘要部分,如下图1和图2所示。我将…

【HTML】交友软件上照片的遮罩是如何做的

笑谈 我不知道大家有没有在夜深人静的时候感受到孤苦难耐&#xff0c;&#x1f436;。于是就去下了一些交友软件来排遣寂寞。可惜的是&#xff0c;有些交友软件真不够意思&#xff0c;连一些漂亮小姐姐的图片都要进行遮罩&#xff0c;完全不考虑兄弟们的感受,&#x1f620;。所…

steam游戏搬砖项目靠谱吗?有没有风险?

作为一款fps射击游戏&#xff0c;csgo在近几年可谓是火出圈&#xff0c;作为一款全球竞技游戏&#xff0c;深受玩家喜爱追捧&#xff0c;玩家追求的就是公平公正&#xff0c;各凭本事&#xff0c;像其他游戏可能还会有皮肤等装备属性加成&#xff0c;在csgo里面是不存在的。 纯…

AI短视频一键换脸小程序源码/带流量主

微信云开发AI一键视频换脸小程序源码是由极客二改后发布的&#xff0c;小程序增加了广告控制&#xff0c;插屏广告&#xff0c;激励广告和原生广告&#xff0c;由于采用了微信云开发没有后台&#xff0c;所以不需要域名和服务器也可以正常搭建使用&#xff0c;所有的配置都可以…

PR:序列的设置

新建序列 序列设置 将视频拖到时间轴上&#xff0c;如果视频的分辨率或帧率和序列设置不一致会有如下提示&#xff0c;保持现有设置即可

卡内基梅隆大学推出模块化爬行机器人,革新天然气管道维护技术!

天然气&#xff0c;作为典型清洁能源代表&#xff0c;在减缓环境污染和应对气候变暖中扮演着关键角色。在众多国家&#xff0c;它已跻身主要能源行列&#xff0c;在工业生产、供暖、电力生成等领埴发挥着核心作用。 天然气管道作为关键的能源传输纽带&#xff0c;为全球数以亿…

【JavaScript】面试手写题精讲之数组(上)

专题缘由 该专题主要是讲解我们在面试的时候碰到一些JS的手写题, 确实这种手写题还是比较恶心的。有些时候好不容易把题目写出来了&#xff0c;突然面试官冷不丁来一句有没有更优的解法&#xff0c;直接让我们僵在原地。为了解决兄弟们的这些困扰&#xff0c;这个专题于是就诞…

MySQL数据库⑩_视图+MySQL用户管理(增删查改)

目录 1. 视图的概念和规则限制 2. 视图的基本使用 2.1 创建视图 2.2 修改视图影响基表 2.3 修改基表影响视图 2.4 删除视图 3. MySQL用户管理 3.1 用户信息 3.2 创建用户 3.3 修改用户密码 3.4 删除用户 4. 用户权限 4.1 MySQL权限 4.2 给用户授权 4.3 回收权限…

imazing怎么连接苹果手机

imazing怎么连接苹果手机 要连接苹果手机&#xff0c;您可以选择使用数据线或无线网络&#xff08;Wi-Fi&#xff09;两种方式。以下是具体的步骤&#xff1a; 使用数据线连接&#xff1a; 准备工具&#xff1a;确保您的Mac或Windows电脑已经安装了iMazing软件&#xff0c;并且…

谷歌浏览器安装扩展程序axure-chrome-extension

注&#xff1a; 文末附扩展附件&#xff1a;axure-chrome-extension_v0.7.0.crx 1、安装扩展程序axure-chrome-extension 找到axure-chrome-extension.crx&#xff0c;把axure-chrome-extension.crx后缀改为zip&#xff0c;然后解压&#xff0c;得到一个文件夹 2、打开谷歌浏览…

OJ_奇怪的餐厅

题干 鲁大师和他的朋友经常去一家奇怪的餐厅&#xff0c;为什么说奇怪呢&#xff0c;一是餐厅提供的菜品比较奇怪&#xff0c;二是餐厅的付费规则比较奇怪&#xff0c;每个人有不同的折扣上限&#xff08;单人从总结里折算的最高金额&#xff09;&#xff0c;超过折扣上限的部…

蓝桥杯嵌入式第12届真题(完成) STM32G431

蓝桥杯嵌入式第12届真题(完成) STM32G431 题目 程序 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body**************************…