前言
昨天被師兄問起程序單元測試的問題, 頓時一臉懵逼, 啥? 單元測試. 折騰了一天, 用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:
-
配置LED(PD12接LED, 低電平點亮): 單擊PD12引腳, 設爲GPIO_Output, 然後右鍵PD12, 選擇Enter User Label, 輸入LEDR:
-
配置串口(Unity測試結果可以通過串口打印出來, 這裏用USART3):
Pinout & Configuration
->Connectivity
->USART3
,Mode
選擇Asynchronous
, 波特率默認115200, 引腳我挪到了板子上對應的PD8,PD9:
-
Project Manager
->Project
->Browse
選擇工程位置(Project Location
), 填入工程名(Project Name
),Toolchain/IDE
選擇MDK-ARM
.
Project Manager
->Code Generator
-> 勾選Copy only the necessary library files
, 還有Generate peripheral initialization as a pair of .c/.h files per periphral
-
點擊右上角
GENERATE CODE
按鈕生成代碼, 打開工程. -
Keil 點擊魔術棒或者
Project
->Options for Target ...
, 默認配置Debug
爲ST-link Debugger
, 點擊Setting
->Flash Download
-> 勾選Reset and Run
, 點擊Pack去掉Enable(聽說是新版Keil的鍋?) 這樣下載後可以自動復位運行.
添加功能代碼
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 <stdio.h>
#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包:
拷貝從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
添加進來:
魔術棒這裏還是要再配置一下的:
接下來把頭文件路徑包含進來:
Drivers/Unity Group添加新文件main1.c, 把main.c的所有內容拷貝到main1.c, 然後main.c右鍵:
去掉Include in Target Build
勾選, 這樣UnitTest
這個Target就不會編譯main.c這個文件了:
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());
}
整個工程的目錄看下來是這樣的:
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 <stdio.h>
#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
編譯下載運行, 可以在串口調試助手中看到測試通過的信息:
如果不通過會顯示:
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
微信公衆號
歡迎掃描二維碼關注本人微信公衆號, 及時獲取或者發送給我最新消息: