目次

ユニットテスト(単体テスト)

CppUTest

ライブラリを作成する際のPlatformはGCCじゃなくてiarでいいのだろうか,
まぁ試してみるが吉なきがする. TrueStudioなら前例あるからMakefileで試したい.
CubeIDE上で静的ライブラリを作ってみることにする.MCUを指定してCppUTestを入れてビルドすればarm-none-eabi-gccでビルドできた. このときのコードはGccでなくGccNoStdCってやつで行った(GCCだとエラー出た) GccNoStdCだとビルドできたしテストしたいコードとリンクもできたけどDebug時にヌルポで死ぬのでダメそう.
GitHubから動くコード見つけてきた(https://github.com/embeddedmz/UnitTestSTM32)
でも参照のソースコードiarにしてあるかつ少し変更を加えていた. GitからCppUTestのコードを拾ってくる以上そっちのコードには手を付けたくないしどうしようかなぁ
G4で試したせいでそもそもG4でなんか動かないのかどうかすらわからない.
本来テストを回すならビルド時にテスト結果見たいんだけどアーキテクチャが違う以上不可能なのだろうか… デバッグで本体つないでその結果をUARTしかりSWVで見ればすでに例があるみたいだけどそれだと組み込みに対してのテスト駆動開発の美味しさがない気もする.

C,C++両方対応してる.
テスト駆動開発による組み込みプログラミングでも例がのってる.

浮動小数点のテスト

How to test for floating point exceptions with CppUTest

Starter Project

少しのMakefileを書くと試せるようになる環境あり
テスト駆動開発による組み込みプログラミングの著者がCppUTestを始めるためのサンプルプロジェクトを作ってくれている

https://matheusmbar.com/bugfree-robot/2019/06/05/a_robot_with_a_purpose.html
CppUTestを使ってPC上でテストコードの実行,そこからドライバIOのMock作成まで試している記事.
cpputest-starter-projectと併用するとわりかし楽にできた.
ビルドするアーキテクチャには注意する.stm32は32bitなので,stm32で動くコードのテストがしたかったらホストでテストするときも32bitでビルドする.
32bitのGCCを使うか,-m32オプションをつける.

Windowsで環境環境を作ってみる

MSYS2上のMinGW64で環境を作る
https://github.com/jwgrenning/cpputest-starter-project  

cd /close-to-your-production-code/cpputest
autoreconf . -i
./configure
make tdd

Autotoolsをインストールしておく。インストールはMSYS2 MinGW(64bit)で入れておく。
上記のコマンドはMSYS2 MinGW x64で起動すること

CubeIDE

Unit Testing in STM32CubeIDE
この記事の方法が現状良さそう.開発しているパソコンの上で動作テストできて,ハードウェアやアーキテクチャの変わる部分はどうしようかと悩んでいたが,全部実行するアーキテクチャの上で走らせて,その結果を読み取れるようにする.
ユニットテストなので,関数で分けて時間依存しないコードとして作る努力をしていけばいいかも.
上記記事の方法で一通りなぞれたのでメモ

CubeIDEを使って,stm32上でCppUtestを走らせる

CppUtestの静的ライブラリ(.aファイル)を作る. 新規プロジェクト作成より,動かすstm32デバイスを選択して,

CppUtestの中身をインクルードし,src/Platforms/Gcc/UTestPlatfrom.cppを追加する.GccNoStdGccとある.
あとはCppUtestのオプションを定義に追加する. CPPUTEST_STD_CPP_LIB_DISABLED
最適化オプションを編集する.
IEEE754ExceptionsPlugin.cpp内のCPPUTEST_HAVE_FENVを無効化し,ビルドする中身を切り替える.
IEEE754ExceptionsPlugin.cppではfenv.hをインクルードして,浮動小数点の例外(ゼロ割,オーバーフロー,アンダーフローなど)検出をテストする.
しかし,ARMのGCC(GNU Arm Embedded Toolchain)に含まれている.fenv.hには浮動小数点計算に使う例外のマクロが無効になっている.
これはCortex-MのFPUにおいて例外処理がハードウェア実装されてることも関係していると思う.(といってもゼロ割だけ)
以上から,ARMでの浮動小数点例外のテストはできないということに注意.
(2023/02/17更新)
arm用のGCCのバージョンが上がったことで、fenv.hの中身も更新された模様。
10-2020-q4-majorでは上記のように例外のマクロがコメントアウトされていたが、10.3-2021.07ではマクロが存在していた。
ということはこのバージョン以降からはIEEE754の浮動小数点例外のテストも実施可能となる?

CubeMXで吐いたコードをもとに静的ライブラリフファイルを出力するMakefileを書いてみた.
出力は上記のCubeIDEでやったおものと同じようなものが出来上がるはず.

表示クリック ⇲

非表示クリック ⇱

Makefile

######################################
# target
######################################
TARGET = cpputest_library
BUILD_ARTIFACT_PREFIX = lib
 
######################################
# building variables
######################################
# debug build?
DEBUG = 0
# optimization
OPT = -O0
 
 
#######################################
# paths
#######################################
# Build path
BUILD_DIR = build
 
######################################
# source
######################################
 
# CPP sources
CPP_SOURCES = \
$(wildcard ../src/CppUTest/*.cpp) \
$(wildcard ../src/CppUTestExt/*.cpp) \
../src/Platforms/Gcc/UtestPlatform.cpp \
 
# C sources
C_SOURCES =  \
 
#######################################
# binaries
#######################################
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
CXX= $(GCC_PATH)/$(PREFIX)g++
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
DP = $(GCC_PATH)/$(PREFIX)objdump
AR = $(GCC_PATH)/$(PREFIX)ar
else
CC = $(PREFIX)gcc
CXX= $(PREFIX)g++
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
DP = $(PREFIX)objdump
AR = $(PREFIX)ar
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
LST = $(DP) -D -Sd
 
#######################################
# CFLAGS
#######################################
# cpu
CPU = -mcpu=cortex-m4
 
# fpu
FPU = -mfpu=fpv4-sp-d16
 
# float-abi
FLOAT-ABI = -mfloat-abi=hard
 
# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
 
# macros for gcc
# AS defines
AS_DEFS = 
 
# C++ defines
CPP_DEFS = -DCPPUTEST_STD_CPP_LIB_DISABLED
 
# AS includes
AS_INCLUDES = 
 
# C++ includes
CPP_INCLUDES = -I../Include
 
# compile g++ flags
CPPFLAGS = $(MCU) $(CPP_DEFS) $(CPP_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CPPFLAGS += -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-use-cxa-atexit -fstack-usage
 
CCACHE := $(shell which ccache)
 
ifeq ($(DEBUG), 1)
CPPFLAGS += -g -gdwarf-2
endif
 
## Generate dependency information
CPPFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
 
all: $(BUILD_DIR)/$(BUILD_ARTIFACT_PREFIX)$(TARGET).a
 
 
#######################################
# build the application
#######################################
# list of c++ objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(CPP_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CPP_SOURCES)))
 
$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR) 
	$(CCACHE) $(CXX) -c $(CPPFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.cpp=.lst)) $< -o $@
 
$(BUILD_DIR)/$(BUILD_ARTIFACT_PREFIX)$(TARGET).a: $(OBJECTS)
	$(AR) -cr $@ $(OBJECTS)
 
$(BUILD_DIR):
	mkdir $@
 
#######################################
# clean up
#######################################
clean:
	-rm -fR $(BUILD_DIR)
 
#######################################
# dependencies
#######################################
-include $(wildcard $(BUILD_DIR)/*.d)
 
# *** EOF ***

参考文献

STM32 プロジェクトの生成からビルド/実行/テスト まで
【丁寧解説】CppUTestをTrueSTUDIOでビルド
Atollic TrueSTUDIOでCppUTestを試す
組み込み環境でのテスト
TDD for microcontrollers in 5 minutes
CppUTest を導入してみる