Unity单元测试初篇

文章目录

    • 前言
    • STM32CubeMX
    • 添加功能代码
    • 加入Unity单元测试
    • 工程链接
    • 微信公众号

前言

昨天被师兄问起程序单元测试的问题, 顿时一脸懵逼, 啥? 单元测试. 折腾了一天, 用Unity好歹撸出来一个HelloWorld级别的LED单元测试, 下面记录下过程, 感觉好久不写博客了, 竟有种无法下笔的感觉, 还是从这篇慢慢拾起来吧.

STM32CubeMX

先用STM32CubeMX 5.6.1建一个工程:

  • MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32F767VITx

  • 调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire

  • Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator(外部用的25M晶振)

  • Clock Configuration:
    Unity单元测试初篇_第1张图片

  • 配置LED(PD12接LED, 低电平点亮): 单击PD12引脚, 设为GPIO_Output, 然后右键PD12, 选择Enter User Label, 输入LEDR:
    Unity单元测试初篇_第2张图片

  • 配置串口(Unity测试结果可以通过串口打印出来, 这里用USART3): Pinout & Configuration -> Connectivity -> USART3, Mode选择Asynchronous, 波特率默认115200, 引脚我挪到了板子上对应的PD8,PD9:
    Unity单元测试初篇_第3张图片

  • Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM.
    Unity单元测试初篇_第4张图片
    Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral
    Unity单元测试初篇_第5张图片

  • 点击右上角 GENERATE CODE 按钮生成代码, 打开工程.

  • Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置DebugST-link Debugger, 点击Setting -> Flash Download -> 勾选Reset and Run, 点击Pack去掉Enable(听说是新版Keil的锅?) 这样下载后可以自动复位运行.
    Unity单元测试初篇_第6张图片
    Unity单元测试初篇_第7张图片

添加功能代码

gpio.c的最下面添加led_on()和led_off()两个函数:

/* USER CODE BEGIN 2 */
GPIO_PinState led_on(void)
{
	HAL_GPIO_WritePin(LEDR_GPIO_Port, LEDR_Pin, GPIO_PIN_RESET);
	return HAL_GPIO_ReadPin(LEDR_GPIO_Port, LEDR_Pin);
}

GPIO_PinState led_off(void)
{
	HAL_GPIO_WritePin(LEDR_GPIO_Port, LEDR_Pin, GPIO_PIN_SET);
	return HAL_GPIO_ReadPin(LEDR_GPIO_Port, LEDR_Pin);
}
/* USER CODE END 2 */

gpio.h声明一下:

/* USER CODE BEGIN Prototypes */
extern GPIO_PinState led_on(void);
extern GPIO_PinState led_off(void);
/* USER CODE END Prototypes */

为了支持printf, 直接在usart.c的最下面添加串口的重定向:

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}
/* USER CODE END 1 */

在main.h添加头文件:

/* USER CODE BEGIN Includes */
#include 
#include "gpio.h"
/* USER CODE END Includes */

在main.c的while(1)里面先测试一下:

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		led_on();
		HAL_Delay(1000);
		led_off();
		HAL_Delay(300);
		printf("hahage\r\n");
  }
  /* USER CODE END 3 */

编译下载, 发现LED闪烁状态正确, 串口115200-8-N-1打印正常.

加入Unity单元测试

这里仅以测试上面的led_on()和led_off()两个函数为例. (为什么都看到灯亮了还测试, 咳咳, 人艰不拆…).

到 Unity Github把master下载下来, 可以git clone https://github.com/ThrowTheSwitch/Unity.git, 也可以直接下载zip包:
Unity单元测试初篇_第8张图片
拷贝从GitHub上拉下来的以下几个文件到上面STM32工程的 /Drivers/Unity(新建的)文件夹里:

  • Unity/src/unity.c
  • Unity/src/unity.h
  • Unity/src/unity_internals.h
  • Unity/src/unity_config.h

打开Keil工程, 点击工程管理按钮, 新添Target: UnitTest, 并点击Set as Current Target按钮, 新添Groups: Drivers/Unity, 然后点击Add Files按钮, 把/Drivers/Unity目录下的unity.c添加进来:
Unity单元测试初篇_第9张图片
魔术棒这里还是要再配置一下的:
Unity单元测试初篇_第10张图片
接下来把头文件路径包含进来:
Unity单元测试初篇_第11张图片
Drivers/Unity Group添加新文件main1.c, 把main.c的所有内容拷贝到main1.c, 然后main.c右键:
Unity单元测试初篇_第12张图片
去掉Include in Target Build勾选, 这样UnitTest这个Target就不会编译main.c这个文件了:
Unity单元测试初篇_第13张图片

Drivers/Unity Group添加新文件test_gpio.c, 添加以下内容:

#include "gpio.h"
#include "unity.h"

void setUp(void)
{
}

void tearDown(void)
{
}

void test_led_on(void)
{
	TEST_ASSERT_EQUAL(GPIO_PIN_RESET, led_on());
	TEST_ASSERT_EQUAL(GPIO_PIN_RESET, led_on());
}

void test_led_off(void)
{
	TEST_ASSERT_EQUAL(GPIO_PIN_SET, led_off());
	TEST_ASSERT_EQUAL(GPIO_PIN_SET, led_off());
}

整个工程的目录看下来是这样的:
Unity单元测试初篇_第14张图片

main1.c添加:

/* USER CODE BEGIN Includes */
#include "unity.h"
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
extern void setUp(void);
extern void tearDown(void);
extern void test_led_on(void);
extern void test_led_off(void);

/*=======Test Reset Option=====*/
void resetTest(void);
void resetTest(void)
{
  tearDown();
  setUp();
}
/* USER CODE END 0 */

  /* USER CODE BEGIN 2 */
	
	UnityBegin("Unit Testing");
	RUN_TEST(test_led_on, __LINE__);
	RUN_TEST(test_led_off, __LINE__);
	
  /* USER CODE END 2 */

打开unity_internals.h, 添加#define UNITY_INCLUDE_CONFIG_H, 表示我们要修改并使用unity_config.h文件:

#define UNITY_INCLUDE_CONFIG_H

#ifdef UNITY_INCLUDE_CONFIG_H
#include "unity_config.h"
#endif

打开unity_config.h文件, 添加以下配置以适配Cortext-M7, 以及测试信息的打印(通过配置的串口):

#define UNITY_EXCLUDE_LIMITS_H
#define UNITY_EXCLUDE_STDINT_H
#define UNITY_INT_WIDTH 32
#define UNITY_POINTER_WIDTH 32
#define UNITY_INCLUDE_FLOAT
#define UNITY_INCLUDE_DOUBLE

#include "main.h"
#include 
#ifdef __GNUC__
 #define UNITY_OUTPUT_CHAR(a)       __io_putchar(a)
#else     
 #define UnityPutc(a)            fputc(a,stdout);
 #define UNITY_OUTPUT_CHAR(a)       UnityPutc(a) 
#endif

编译下载运行, 可以在串口调试助手中看到测试通过的信息:
Unity单元测试初篇_第15张图片
如果不通过会显示:

Unit Testing:103:test_led_on:PASS
Unit Testing:20:test_led_off:FAIL: Expected 1 Was 0

表示led_off()函数测试失败.

工程链接

https://download.csdn.net/download/weifengdq/12439854

微信公众号

欢迎扫描二维码关注本人微信公众号, 及时获取或者发送给我最新消息:
在这里插入图片描述

你可能感兴趣的:(单元测试,Unity,单元测试,C,STM32Cube,HAL)