Unity简介:
Unity是一个用于C语言的轻量级单元测试框架。它由Throw The Switch团队开发,旨在简化嵌入式系统的单元测试。单元测试中单元的含义,单元就是人为规定的最小的被测功能模块,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。在实际项目中,单元测试往往由开发人员完成。
Unity的设计目标是易于使用、轻便、可移植,并能够在各种嵌入式和非嵌入式系统中运行。核心项目是一个 C 文件和一对头文件,允许将其添加到现有的构建设置中,而不会太麻烦。 可以使用任何想用的编译器,并且可以使用大多数现有的构建系统,包括 Make、CMake 等。
Unity简单使用方法:
1、下载unity框架
去GitHub下载,或者gti clone到本地,链接地址:unity。
Unity 本身非常小。 其他剩下的只是可选附加组件。 可以忽略它或在方便时使用它。 以下是项目中所有内容的概述。
- src- 这是你关心的代码!此文件夹包含一个 C 文件和两个头文件。 这三个文件是 Unity。
- docs- 在这里可以找到所有方便的文档。
- examples- 这包含一些使用 Unity 的示例。
- extras- 这些是 Unity 的可选附加组件,不属于核心项目。
- test- 这就是 Unity 及其脚本的测试方式。 如果你只是使用Unity,你可能永远不需要进入这里。
- auto- 在这里,你将找到有用的 Ruby 脚本,以简化你的测试工作流程。 它们完全是可选的,不需要使用 Unity。
2、使用unity框架
测试文件是 C 文件。 大多数情况下,将为每个要测试的 C 模块创建一个测试文件。 测试文件应包含 unity.h 和要测试的 C 模块的标头。
例如测试下面两个函数:
ProductionCode.c
#include "ProductionCode.h" int Counter = 0; int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; /* some obnoxious array to search that is 1-based indexing instead of 0. */ /* This function is supposed to search through NumbersToFind and find a particular number. * If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since * NumbersToFind is indexed from 1. Unfortunately it's broken * (and should therefore be caught by our tests) */ int FindFunction_WhichIsBroken(int NumberToFind) { int i = 0; while (i < 8) /* Notice I should have been in braces */ i++; if (NumbersToFind[i] == NumberToFind) /* Yikes! I'm getting run after the loop finishes instead of during it! */ return i; return 0; } int FunctionWhichReturnsLocalVariable(void) { return Counter; }
ProductionCode.h
#ifndef _PRODICTIONCODE_H_ #define _PRODICTIONCODE_H_ extern int Counter; int FindFunction_WhichIsBroken(int NumberToFind); int FunctionWhichReturnsLocalVariable(void); #endif
接下来,测试文件将包含测试例程函数。 setUp 函数可以包含你希望在每次测试之前运行的任何内容。 tearDown 函数可以包含你希望在每次测试后运行的任何内容。 这两个函数都不接受任何参数,也不返回任何内容。 如果不需要它们,将其设置为空。setUp() tearDown()
TestProductionCode.h
#include "ProductionCode.h" #include "unity.h" /* sometimes you may want to get at local data in a module. * for example: If you plan to pass by reference, this could be useful * however, it should often be avoided */ extern int Counter; void setUp(void) { /* This is run before EACH TEST */ Counter = 0x5a5a; } void tearDown(void) { } void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void) { /* All of these should pass */ TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78)); TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(2)); TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33)); TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999)); TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1)); } void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void) { /* You should see this line fail in your test summary */ TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34)); /* Notice the rest of these didn't get a chance to run because the line above failed. * Unit tests abort each test function on the first sign of trouble. * Then NEXT test function runs as normal. */ TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888)); } void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void) { /* This should be true because setUp set this up for us before this test */ TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); /* This should be true because we can still change our answer */ Counter = 0x1234; TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); } void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void) { /* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */ TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); } void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void) { /* Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell * you what actually happened...which in this case was a failure to setup the initial condition. */ TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); }
最后,在编写main函数,然后调用每个测试例程函数。 这实际上会触发每个测试例程函数运行,因此每个函数都有自己的调用非常重要。
/* AUTOGENERATED FILE. DO NOT EDIT. */ /*=======Automagically Detected Files To Include=====*/ #include "unity.h" #include
#include #include "ProductionCode.h" /*=======External Functions This Runner Calls=====*/ extern void setUp(void); extern void tearDown(void); extern void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void); extern void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void); extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void); extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void); extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void); /*=======MAIN=====*/ int main(void) { UnityBegin("test/TestProductionCode.c"); RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode); RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken); RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue); RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain); RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed); return (UnityEnd()); } 3、构建运行环境
创建一个目录 TDDUnityExample,在TDDUnityExample 目录下创建 CMakeLists.txt 文件。
# 最低CMake版本要求 cmake_minimum_required(VERSION 3.15) #将Unity/src工作目录的源文件赋给UNITY_SRC_LIST #将Tests工作目录的源文件赋给APP_SRC_DIR aux_source_directory (Unity/src UNITY_SRC_LIST) aux_source_directory (Tests APP_SRC_DIR) # 项目名称 project(TDD_test) # 头文件路径 include_directories(Unity/src) #将所有源文件生成一个可执行文件 add_executable(TDD_test ${APP_SRC_DIR} ${UNITY_SRC_LIST}) set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
在 TDDUnityExample 下创建 Unity 目录,然后将Unity 框架源码中的 src 目录拷贝到 Unity目录中。
在 TDDUnityExample 下创建 Tests 目录,然后将第二点中举例的测试文件都放在 Tests 目录中。
在 TDDUnityExample 下创建 build 目录,然后在 build 目录下也创建一个 CMakeLists.txt 文件。
cmake_minimum_required (VERSION 2.8) project (TDD_test) add_subdirectory (Tests)
最后整体文件结构如下:
├── build │ └── CMakeLists.txt ├── CMakeLists.txt ├── Tests │ ├── ProductionCode.c │ ├── ProductionCode.h │ ├── TestProductionCode.c │ └── TestProductionCode_Runner.c └── Unity └── src ├── meson.build ├── unity.c ├── unity.h └── unity_internals.h
4、运行测试程序
在 build 目录下输入 cmake ..命令,会自动生成 Makefile 文件,然后输入make,就会自动编译生成可执行文件 TDD_test 在 TDDUnityExample /bin 下。
进入 TDDUnityExample /bin 下,输入./TDD_test。
输出结果为:
test/TestProductionCode.c:0:test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode:PASS test/TestProductionCode.c:33:test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken:FAIL: Expected 1 Was 0 test/TestProductionCode.c:0:test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue:PASS test/TestProductionCode.c:0:test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain:PASS test/TestProductionCode.c:61:test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed:FAIL: Expected 0x00001234 Was 0x00005A5A ----------------------- 5 Tests 2 Failures 0 Ignored FAIL
从结果来看第二个和第五个测试例程出现错误,错误原因也标记出来了。
5、常用断言
TEST_PASS(); /* 中止测试的其余部分, 但将测试计为通过 */ TEST_PASS_MESSAGE("message") TEST_IGNORE(); /* 将测试用例标记为忽略, 但将测试计为通过 */ TEST_PASS_MESSAGE("message") TEST_FAIL(); /* 中止测试的其余部分, 但将测试计为失败 */ TEST_FAIL_MESSAGE("message") TEST_MESSAGE(""); /* 将消息输出 */
以上断言宏都是放在编写的测试函数中,TEST_IGNORE 一般放在函数的顶部,用来表示将测试用例忽略,其他宏可以放在函数的任意位置。
总结:
unity单元测试框架核心是一个 C 文件和一对头文件,特点是简洁易用、轻量级、可移植性、支持测试断言等。其中有许多测试断言需要多了解多使用。
好了以上就是Unity单元测试框架的简易使用方法,有什么疑问和建议欢迎在评论区中提出,想要了解更多的Unity知识可以去官网上查看,官网上也有详细的教程和实例。
猜你喜欢
网友评论
- 搜索
- 最新文章
- 热门文章