日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

μCUnit,微控制器的单元测试框架

發布時間:2025/5/22 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 μCUnit,微控制器的单元测试框架 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  在MCU on Eclipse網站上看到Erich Styger在8月26日發布的博文,一篇關于微控制器單元測試的文章,有很高的參考價值,特將其翻譯過來以備學習。原文網址:https://mcuoneclipse.com/2018/08/26/tutorial-%CE%BCcunit-a-unit-test-framework-for-microcontrollers/

?

  單元測試是主機開發的常見做法。但對于嵌入式開發,這似乎仍然是一個“空白”領域。主要是因為嵌入式工程師不習慣單元測試,或者因為單元測試的通??蚣苄枰度胧侥繕松系奶噘Y源?

  我使用的是μCUnit框架,它是一個小巧易用的框架,面向小型微控制器應用。

?

uCUnit

  框架非常簡單:兩個頭文件和一個.c文件:

?

uCUnit框架文件

?

  使用uCUnit GitHub站點中的原始站點或使用我從GitHub稍微調整和修改的站點,以與MCUXpresso SDK和IDE一起使用。

  概念是單元測試包括提供測試宏的uCunit.h頭文件。

  頭文件中的#define將輸出配置為詳細或正常:

?

UCUNIT_MODE_NORMAL或UCUNIT_MODE_VERBOSE

?

  System.c和System.h是系統的連接,主要用于啟動,關閉和打印測試結果到控制臺。下面是使用printf()方法寫入輸出的實現,但是這可以被任何寫入例程替換或擴展到SD卡上的日志文本。

1 /* Stub: Transmit a string to the host/debugger/simulator */ 2 void System_WriteString(char * msg) { 3 4 PRINTF(msg); 5 6 } 7 8 void System_WriteInt(int n) { 9 10 PRINTF("%d", n); 11 12 }

框架概述

  首先,我必須包含單元測試框架頭文件:

#include "uCUnit.h"

  接著,我必須初始化框架

UCUNIT_Init(); /* initialize framework */

  還有一個測試用例包含在UCUNIT_TestcaseBegin()和UCUNIT_TestcaseEnd()中:

UCUNIT_TestcaseBegin("Crazy Scientist");

/* test cases ... */

UCUNIT_TestcaseEnd();

  在最后使用時寫一個摘要

UCUNIT_WriteSummary();

  如果系統應該關閉使用a

UCUNIT_Shutdown();

測試

  該框架提供了多種測試方法,例如:

UCUNIT_CheckIsEqual(x, 0); /* check if x == 0 */

UCUNIT_CheckIsInRange(x, 0, 10); /* check 0 <= x <= 10 */

UCUNIT_CheckIsBitSet(x, 7); /* check if bit 7 set */

UCUNIT_CheckIsBitClear(x, 7); /* check if bit 7 cleared */

UCUNIT_CheckIs8Bit(x); /* check if not larger then 8 bit */

UCUNIT_CheckIs16Bit(x); /* check if not larger then 16 bit */

UCUNIT_CheckIs32Bit(x); /* check if not larger then 32 bit */

UCUNIT_CheckIsNull(p); /* check if p == NULL */

UCUNIT_CheckIsNotNull(s); /* check if p != NULL */

UCUNIT_Check((*s)==’\0’, "Missing termination", "s"); /* generic check: condition, msg, args */

  通過幾個例子可以解釋這一點。

示例:瘋狂的科學家

  下面是一個'crazyScientist'功能,它結合了不同的材料:

1 typedef enum { 2 Unknown, /* first, generic item */ 3 Hydrogen, /* H */ 4 Helium, /* He */ 5 Oxygen, /* O */ 6 Oxygen2, /* O2 */ 7 Water, /* H2O */ 8 ChemLast /* last, sentinel */ 9 } Chem_t; 10 11 Chem_t crazyScientist(Chem_t a, Chem_t b) { 12 if (a==Oxygen && b==Oxygen) { 13 return Oxygen2; 14 } 15 16 if (a==Hydrogen && b==Oxygen2) { 17 return Water; 18 } 19 20 return Unknown; 21 22 }

  對此的測試可能如下所示:

1 void Test(void) { 2 Chem_t res; 3 UCUNIT_Init(); /* initialize framework */ 4 5 UCUNIT_TestcaseBegin("Crazy Scientist"); 6 res = crazyScientist(Oxygen, Oxygen); 7 UCUNIT_CheckIsEqual(res, Oxygen2); 8 UCUNIT_CheckIsEqual(Unknown, crazyScientist(Water, Helium)); 9 UCUNIT_CheckIsEqual(Water, crazyScientist(Hydrogen, Oxygen2)); 10 UCUNIT_CheckIsEqual(Water, crazyScientist(Oxygen2, Hydrogen)); 11 UCUNIT_CheckIsInRange(crazyScientist(Unknown, Unknown), Unknown, ChemLast); 12 UCUNIT_TestcaseEnd(); 13 14 /* finish all the tests */ 15 UCUNIT_WriteSummary(); 16 UCUNIT_Shutdown(); 17 }

  通過不同的檢查,我們可以驗證功能是否正在按照我們的預期進行。它產生以下輸出:

======================================

Crazy Scientist

======================================

../source/Application.c:60: passed:IsEqual(res,Oxygen2)

../source/Application.c:61: passed:IsEqual(Unknown,crazyScientist(Water, Helium))

../source/Application.c:62: passed:IsEqual(Water,crazyScientist(Hydrogen, Oxygen2))

../source/Application.c:63: failed:IsEqual(Water,crazyScientist(Oxygen2, Hydrogen))

../source/Application.c:64: passed:IsInRange(crazyScientist(Unknown, Unknown),Unknown,ChemLast)

======================================

../source/Application.c:65: failed:EndTestcase()

======================================

?

**************************************

Testcases: failed: 1

?????????? passed: 0

Checks:??? failed: 1

?????????? passed: 4

**************************************

System shutdown.

  我建議在執行之前編寫單元測試*,因為這樣我就可以考慮所有不同的極端情況并改進要求。

  以上輸出設置為UCUNIT_MODE_VERBOSE。使用UCUNIT_MODE_NORMAL,它使用更緊湊的格式并僅打印失敗的測試:

======================================

Crazy Scientist

======================================

../source/Application.c:63: failed:IsEqual(Water,crazyScientist(Oxygen2, Hydrogen))

======================================

../source/Application.c:65: failed:EndTestcase()

======================================

?

**************************************

Testcases: failed: 1

?????????? passed: 0

Checks:??? failed: 1

?????????? passed: 4

**************************************

System shutdown.

跟蹤點

  在上面的例子中,我們只是從外部測試函數的功能。如何檢查以下函數中的測試確實檢查除以零的情況?

1 int checkedDivide(int a, int b) { 2 if (b==0) { 3 PRINTF("division by zero is not defined!\n"); 4 return 0; 5 } 6 return a/b; 7 }

  要檢查是否真的輸入了if()條件,我可以添加一個跟蹤點。跟蹤點的數量在μCUnit.h中配置為:

/**

?* Max. number of checkpoints. This may depend on your application

?* or limited by your RAM.

?*/

#define UCUNIT_MAX_TRACEPOINTS 16

  和

UCUNIT_ResetTracepointCoverage();

  我可以重置跟蹤點。

  我用跟蹤標記執行跟蹤點(在0..UCUNIT_MAX_TRACEPOINTS-1范圍內)

UCUNIT_Tracepoint(id);

  和

UCUNIT_CheckTracepointCoverage(0);

  我可以檢查是否觸摸了給定的跟蹤點。在要測試的功能下面有一個跟蹤點:

1 int checkedDivide(int a, int b) { 2 if (b==0) { 3 UCUNIT_Tracepoint(0); /* mark trace point */ 4 PRINTF("division by zero is not defined!\n"); 5 return 0; 6 } 7 return a/b; 8 }

  相應的單元測試代碼:

1 UCUNIT_TestcaseBegin("Checked Divide"); 2 UCUNIT_CheckIsEqual(100/5, checkedDivide(100,5)); 3 UCUNIT_ResetTracepointCoverage(); /* start tracking */ 4 UCUNIT_CheckIsEqual(0, checkedDivide(1024,0)); 5 UCUNIT_CheckTracepointCoverage(0); /* check coverage of point 0 */ 6 UCUNIT_TestcaseEnd();

  然后生成:

======================================

Checked Divide

======================================

../source/Application.c:69: passed:IsEqual(100/5,checkedDivide(100,5))

division by zero is not defined!

../source/Application.c:71: passed:IsEqual(0,checkedDivide(1024,0))

../source/Application.c:72: passed:TracepointCoverage(1)

字符串測試

  還有許多其他方法可以使用檢查,最多可以使用用戶配置的檢查和消息。以下是要測試的函數的示例:

1 char *endOfString(char *str) { 2 if (str==NULL) { 3 return NULL; 4 } 5 while(*str!='\0') { 6 str++; 7 } 8 return str; 9 }

  使用以下測試代碼:

1 UCUNIT_TestcaseBegin("Strings"); 2 UCUNIT_CheckIsNull(endOfString(NULL)); 3 str = endOfString("abc"); 4 UCUNIT_Check( 5 (str!=NULL), /* condition to check */ 6 "string shall be not NULL", /* message */ 7 "str" /* argument as string */ 8 ); 9 UCUNIT_CheckIsEqual('\0', *endOfString("")); 10 UCUNIT_CheckIsEqual('\0', *endOfString("hello")); 11 str = endOfString("world"); 12 UCUNIT_CheckIsNotNull(str); 13 UCUNIT_CheckIsEqual('\0', *str); 14 UCUNIT_TestcaseEnd();

  其輸出:

======================================

Strings

======================================

../source/Application.c:76: passed:IsNull(endOfString(NULL))

../source/Application.c:82: passed:string shall be not NULL(str)

../source/Application.c:83: passed:IsEqual('\0',*endOfString(""))

../source/Application.c:84: passed:IsEqual('\0',*endOfString("hello"))

../source/Application.c:86: passed:IsNotNull(str)

../source/Application.c:87: passed:IsEqual('\0',*str)

概要

  μCUnit是一個非常簡單但功能強大的嵌入式設備和微控制器單元測試框架。它易于使用,只需要極少的資源,并通過自動化單元測試幫助提高嵌入式軟件的質量。我希望你也覺得它很有用。

鏈接

  • μCUnit網頁:http://www.ucunit.org/
  • μCUnit文檔:http://www.ucunit.org/_documentation.html
  • μCUnitGithub網站:https://github.com/ucunit/ucunit
  • μCUnit示例用法:https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/FRDM-K64F/FRDM-K64F_uCUnit
  • 適用于MCUXpresso的μCUnit端口:https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/FRDM-K64F/FRDM-K64F_uCUnit/uCUnit

歡迎關注:

轉載于:https://www.cnblogs.com/foxclever/p/9573026.html

總結

以上是生活随笔為你收集整理的μCUnit,微控制器的单元测试框架的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。