前沿
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。
在网上找了找C语言都没有类似java 的junit单元测试 ,反复测试自己写的模块非常费劲,特别是交叉模块测试的时候根本就无法弄
因为一个程序只允许一个main方法,如果其他地方存在了,那么就会报错,这就导致了测完A模块想要测试B模块就需要把A模块测试的相关内容删除,这样会出现什么问题呢? 如果后期我们对A模块的内容进行了修改,那么是不是需要在重新写一套测试Demo, 这样非常浪费时间和精力 ,没办法只能自己开发一套类似的,来协助本地开发进行测试代码
- 实现最小单元以函数进行测试
- 实现流程测试
- 实现模块交互模块测试
使用前提
自己必须有集合数据结构和hash结构,然后根据下面的代码进行修改即可 ,如果没有可以到我博客里学习
测试结构
断言
#ifndef STUDY_ASSERTMY_H
#define STUDY_ASSERTMY_H
//设置字体颜色 (只是在windward下有效)
#define color(x) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x)
#define assertErrorMessageTest(_Expression,errorMessage) \
do \
{
\
if((_Expression)){
\
color(2) ;\
printf("==============================: method:%s ---> (%s)Assertion success\n ",__func__,#_Expression); \
} ; \
color(7);\
if(!(_Expression)){
\
color(4) ;\
printf("==============================: (%s)\n Assertion failed: (%s), file:%s \nmethod:%s , line %d \n", errorMessage, #_Expression, __FILE__,__func__ , __LINE__) ; \
exit(0); \
color(7); \
} ; \
} while(0)
#define assertMessageMoreTest(_Expression,correctMessage, errorMessage) \
do \
{
\
if((_Expression)){
\
color(2) ;\
printf("==============================: (%s)\n Assertion success: (%s) , method:%s \n ",correctMessage,__func__,#_Expression); \
} ; \
color(7);\
if(!(_Expression)){
\
color(4) ;\
printf("==============================: (%s)\n Assertion failed: (%s), file:%s \nmethod:%s , line %d \n", errorMessage, #_Expression, __FILE__,__func__ , __LINE__) ; \
exit(0); \
color(7); \
} ; \
} while(0)
#define assertTest(_Expression) \
do \
{
\
if(!(_Expression)){
\
color(4) ;\
printf("Assertion failed: (%s), file:%s \nmethod:%s , line %d \n", #_Expression, __FILE__,__func__ , __LINE__) ; \
exit(0); \
color(7); \
} ; \
} while(0)
#endif //STUDY_ASSERTMY_H
核心代码
#ifndef STUDY_TESTCORE_H
#define STUDY_TESTCORE_H
#include "../../structure/charlinkedhashmap.h"
#include "../../structure/char_kv_orderly_list.h"
#include "../assertmy.h"
#include <windows.h>
typedef int BOOL;//定义一个布尔类型
#define TRUE 1
#define FALSE 0
typedef void (*TestMethod)(void);
typedef void (TestGroupMethod)(void);
typedef struct testCore {
char methodName[100]; //方法名
BOOL methodState; //方法状态
void *method; //方法
} TestCore;
typedef struct testGroup {
char groupName[100]; //组名
BOOL groupState; //组状态
} TestGroup;
void addTestGroup(char *testGroupName,BOOL state, Long order, TestGroupMethod testGroupMethod);
void test_Run_Core_MethodAll();
void test_Run_Core_Method(char *methodName);
void addTestMethodName( const char *groupId, char *methodName, BOOL state, Long order, TestMethod testMethod);
void test_Run_Core_Group(char *testGroupName);
void test_Run_Core_Group_ALL();
#endif //STUDY_TESTCORE_H
#include "testcore.h"
#include <string.h>
#include "assert.h"
static CharLinkedHashMap *testCore = NULL;
static CharKvOrderlyList *testGroup = NULL;
#define MAXSCORE 2147483647
#define MINCORE -2147483648
#define LIMIT(x) (assert(x>=MINCORE&&x<=MAXSCORE))
Long groupCount = 1; //记录第几组
#define addOrder(x) x->sort=groupCount*MAXSCORE+x->sort;
//创建测试核心
TestCore *createTestCore(char *methodName, BOOL state, TestMethod testMethod) {
TestCore *testCore = malloc(sizeof(TestCore));
testCore->methodState = state;
testCore->method = testMethod;
strcpy(testCore->methodName, methodName);
return testCore;
}
//创建测试组
TestGroup *createTestGroup(char *groupName, BOOL state) {
TestGroup *testGroup = malloc(sizeof(TestGroup));
testGroup->groupState = state;
strcpy(testGroup->groupName, groupName);
return testGroup;
}
/**
*
* @param groupId __FUNCTION__ 使用宏获取当前方法名代来作为测试组名
* @param methodName 方法名
* @param testMethod 需要运行的方法
* @param state 方法状态TRUE启用 FALSE禁用
* @param order 执行的顺序 (值越大越靠后)
*/
void addTestMethodName(const char *groupId, char *methodName, BOOL state, Long order, TestMethod testMethod) {
LIMIT(order); //判定order是否在范围内
if (testCore == NULL) {
testCore = createCharLinkedHashMap(200);
}
void *pVoid = getCharLinkedHashMap(testCore, groupId);
if (pVoid == NULL) {
CharKvOrderlyList *pList = createCharKvOrderlyList(200);
TestCore *pCore = createTestCore(methodName, state, testMethod);
addCharKvOrderlyList(pList, methodName, pCore, order);
putCharLinkedHashMap(testCore, groupId, pList);
} else {
CharKvOrderlyList *pList = (CharKvOrderlyList *) pVoid;
TestCore *pCore = createTestCore(methodName, state, testMethod);
addCharKvOrderlyList(pList, methodName, pCore, order);
}
}
/**
* 运行指定的测试方法
* @param methodName
* @param initMethod
*/
void test_Run_Core_Method(char *methodName) {
CharList *pCharlist = keysCharLinkedHashMap(testCore);
//迭代测试组
for (int i = 0; i < pCharlist->len; i++) {
char *groupId = pCharlist->str[i];
CharKvOrderlyList *pList = getCharLinkedHashMap(testCore, groupId);
CharKvOrderlyListData *pData = getCharKvOrderlyListByKey(pList, methodName);
if(pData!=NULL){
TestCore *testCore1 = (TestCore *) pData->data;
TestMethod pVoid = testCore1->method;
pVoid();
return;
}
}
}
/**
* 运行所有的测试方法,如果方法状态为FALSE则跳过
* @param initMethod
*/
void test_Run_Core_MethodAll() {
//根据指定的顺序执行
CharLinkedHashIterator *pHashIterator = createCharLinkedHashMapIterator(testCore);
while (hasNextCharLinkedHashMapIterator(pHashIterator)) {
CharKvLinkedNode *pNode = nextCharLinkedHashMapIterator(pHashIterator);//拿到方法名
//拿到测试组的方法并且运行
CharKvOrderlyListIterator *pListIterator = createCharKvOrderlyListIterator(pNode->value);
while (hasNextCharKvOrderlyList(pListIterator)) {
CharKvOrderlyListData *pData = (CharKvOrderlyListData *) nextCharKvOrderlyList(pListIterator);//拿到方法名
TestCore *testCore1 = pData->data;
if (testCore1->methodState == TRUE) {
TestMethod pVoid = testCore1->method;
pVoid();
}
}
}
}
//添加测试组
void addTestGroup(char *testGroupName,BOOL state, Long order, TestGroupMethod testGroupMethod) {
if (testGroup == NULL) {
testGroup = createCharKvOrderlyList(200);
}
testGroupMethod();//执行测试组方法载入测试容器里面
//添加测试组
TestGroup *testGroup1 = createTestGroup(testGroupName, state);
addCharKvOrderlyList(testGroup, testGroupName, testGroup1, order);
//获取组内的所有的方法,然后从新计算排序分值
CharKvOrderlyList *pNode = (CharKvOrderlyList *) getCharLinkedHashMap(testCore, testGroupName);
CharKvOrderlyListIterator *pListIterator = createCharKvOrderlyListIterator(pNode);
while (hasNextCharKvOrderlyList(pListIterator)) {
CharKvOrderlyListData *pData = (CharKvOrderlyListData *) nextCharKvOrderlyList(pListIterator);//拿到方法名
addOrder(pData);
}
groupCount++;
quickSort(pNode); //重新排序
}
void test_Run_Core_Group(char *testGroupName) {
CharKvOrderlyList *pNode = (CharKvOrderlyList *) getCharLinkedHashMap(testCore, testGroupName);
if(pNode==NULL){
return;
}
//拿到测试组的方法并且运行
CharKvOrderlyListIterator *pListIterator = createCharKvOrderlyListIterator(pNode);
while (hasNextCharKvOrderlyList(pListIterator)) {
CharKvOrderlyListData *pData = (CharKvOrderlyListData *) nextCharKvOrderlyList(pListIterator);//拿到方法名
TestCore *testCore1 = pData->data;
if (testCore1->methodState == TRUE) {
TestMethod pVoid = testCore1->method;
pVoid();
}
}
}
void test_Run_Core_Group_ALL() {
//根据指定的顺序执行
CharKvOrderlyListIterator *pListIterator = createCharKvOrderlyListIterator(testGroup);
while (hasNextCharKvOrderlyList(pListIterator)) {
CharKvOrderlyListData *pData = (CharKvOrderlyListData *) nextCharKvOrderlyList(pListIterator);//拿到方法名
TestGroup *testGroup1 = (TestGroup *) pData->data;
if (testGroup1->groupState == TRUE) {
test_Run_Core_Group(testGroup1->groupName);
}
}
}
测试组装工厂
#ifndef STUDY_TESTFACTORY_H
#define STUDY_TESTFACTORY_H
#include "../structure/charlinkedhashmap.h"
#include "../structure/char_kv_orderly_list.h"
#include "testcore/testcore.h"
typedef void(*TestFun)(void);
void test_Run_Method(char *methodName);
void test_Run_GroupAll_MethodAlL();
void test_Run_Group(char *groupMethodName);
void testMain(TestFun testFun);
#endif //STUDY_TESTFACTORY_H
#include "testfactory.h"
#include <stdio.h>
static BOOL test_init_of=FALSE;//测试初始化
void test_Run_Method(char *methodName){
assertTest(test_init_of);
test_Run_Core_Method(methodName);
}
void test_Run_GroupAll_MethodAlL(){
assertTest(test_init_of);
test_Run_Core_MethodAll();
}
void test_Run_Group(char *groupMethodName){
assertTest(test_init_of);
test_Run_Core_Group(groupMethodName);
}
void testMain(TestFun testFun){
testFun();
test_init_of=TRUE;
}
编写测试Demo(演示)
#ifndef STUDY_TEST_CHARLIST_DEMO_H
#define STUDY_TEST_CHARLIST_DEMO_H
void test_charlist_demo_init_method();
#endif //STUDY_TEST_CHARLIST_DEMO_H
#include "test_charlist_demo.h"
#include "../../structure/charlist.h"
#include <stdio.h>
#include "../testcore/testcore.h"
static CharList *pCharlist;
void test_create_charlist_demo() {
pCharlist = createCharList(200);
assertErrorMessageTest(pCharlist, "createCharList创建失败");
}
void test_add_charlist_demo() {
char *str = "hello";
char *str2 = "world";
char *str3 = "!";
char *str4 = "hu";
char *str5 = "an";
char *str6 = "min";
addCharList(pCharlist, str);
addCharList(pCharlist, str2);
addCharList(pCharlist, str3);
addCharList(pCharlist, str4);
addCharList(pCharlist, str5);
addCharList(pCharlist, str6);
assertErrorMessageTest(pCharlist->len == 6, "addCharList添加失败");
}
void test_get_charlist_demo() {
char *str = "hello";
int i = charListBinarySearch(pCharlist, str);
char message[100];
sprintf(message, "charListBinarySearch查找成功,查找的位置为%d", i);
assertMessageMoreTest(i != -1,message, "charListBinarySearch查找失败");
}
void test_del_charlist_demo() {
char *str = "hello";
int value = deleteCharListByValue(pCharlist, str);
char message[100];
sprintf(message, "deleteCharListByValue删除成功,删除的位置为%d", value);
assertMessageMoreTest(value,message, "delCharList删除失败");
}
void test_del_index_charlist_demo() {
int i = deleteCharListByIndex(pCharlist, 0);
char message[100];
sprintf(message, "deleteCharListByIndex删除成功,删除的位置为%d", i);
assertMessageMoreTest( i !=-1,message, "delCharListByIndex删除失败");
}
void test_print_charlist_demo() {
printCharList(pCharlist);
char message[100]="test_print_charlist_demo处理完毕";
assertMessageMoreTest(pCharlist->len > 0,message, "test_print_charlist_demo处理失败");
}
//因为原有的字符串是系统创建的内存,所以不能修改,所以需要复制一份,给够空间,然后再修改
static char * func(char * str){
char * st1 = (char *)malloc(15);
strcpy(st1, str);
return strcat(st1,"1") ;
}
void test_forEachCharList_demo() {
forEachCharList(pCharlist, func);
char message[100]="test_forEachCharList_demo处理完毕";
assertMessageMoreTest(pCharlist->len > 0,message, "test_forEachCharList_demo处理失败");
}
void test_charListClean_demo() {
charListClean(pCharlist);
char message[100];
sprintf(message, "charListClean清空成功,长度为%d", pCharlist->len);
assertMessageMoreTest(pCharlist->len == 0,message, "charListClean清空失败");
}
void test_charListIndexOf_demo() {
char *str = "hu";
int i = charListIndexOf(pCharlist, str);
char message[100];
sprintf(message, "charListIndexOf查找成功,查找的位置为%d", i);
assertMessageMoreTest(i == -1,message , "charListIndexOf查找失败");
}
void test_charListLastIndexOf_demo() {
char *str = "hu";
int i = charListLastIndexOf(pCharlist, str);
char message[100];
sprintf(message, "charListLastIndexOf查找成功,查找的位置为%d", i);
assertMessageMoreTest(i == -1, message , "charListLastIndexOf查找失败");
}
void test_charListIsSorted_demo() {
BOOL pd = charListIsSorted(pCharlist,TRUE,TRUE);
char message[100];
sprintf(message, "charListIsSorted判断数组是否有序 %d", pd);
assertMessageMoreTest(pd, message , "charListIsSorted判断数组是否有序失败");
}
void test_charListBinarySearch_demo() {
char *str = "hu";
int i = charListBinarySearch(pCharlist, str);
char message[100];
sprintf(message, "charListBinarySearch查找成功,查找的位置为%d", i);
assertMessageMoreTest(i == -1, message , "charListBinarySearch查找失败");
}
void test_charListSet_demo() {
char *str = "hu1111";
charListSet(pCharlist, str,0);
char message[100];
sprintf(message, "charListSet设置成功,设置后的值为%s", pCharlist->str[0]);
assertMessageMoreTest( strcmp(pCharlist->str[0],"hu1111")==0, message , "charListSet设置失败");
}
void test_quickSortCharList_demo() {
charListSort(pCharlist,TRUE);
char message[100];
sprintf(message, "quickSortCharList排序成功");
assertMessageMoreTest( pCharlist->len > 0, message , "quickSortCharList排序失败");
}
void test_charListReverse_demo() {
charListReverse(pCharlist);
char message[100];
sprintf(message, "charListReverse反转成功");
assertMessageMoreTest( pCharlist->len > 0, message , "charListReverse反转失败");
}
void test_charListCopy_demo() {
CharList *pCharlist1 = charListCopy(pCharlist);
char message[100];
sprintf(message, "charListCopy复制成功");
assertMessageMoreTest( pCharlist1->len > 0, message , "charListCopy复制失败");
}
void test_charListDistinct_demo() {
charListDistinct(pCharlist);
char message[100];
sprintf(message, "charListDistinct去重成功");
assertMessageMoreTest( pCharlist->len > 0, message , "charListDistinct去重失败");
}
void test_charListMerge_demo() {
CharList *pCharlist1 = charListCopy(pCharlist);
CharList *merge = charListMerge(pCharlist, pCharlist1);
char message[100];
sprintf(message, "charListMerge合并成功,长度为%d", merge->len);
assertMessageMoreTest( merge->len > 0, message , "charListMerge合并失败");
}
void test_charListDifference_demo() {
CharList *pCharlist1 = charListCopy(pCharlist);
addCharList(pCharlist, "hu1344");
addCharList(pCharlist, "h222u1344");
CharList *difference = charListDifference(pCharlist, pCharlist1);
char message[100];
sprintf(message, "charListDifference差集成功,长度为%d", difference->len);
assertMessageMoreTest( difference->len > 0, message , "charListDifference差集失败");
}
void test_charListComplement_demo() {
CharList *pCharlist1 = charListCopy(pCharlist);
addCharList(pCharlist1, "12345");
addCharList(pCharlist1, "把231");
CharList *complement = charListComplement(pCharlist, pCharlist1);
char message[100];
sprintf(message, "charListComplement补集成功,长度为%d", complement->len);
assertMessageMoreTest( complement->len > 0, message , "charListComplement补集失败");
}
void test_charListUnion_demo() {
CharList *pCharlist1 = charListCopy(pCharlist);
addCharList(pCharlist1, "12345");
addCharList(pCharlist1, "把231");
CharList *unionList = charListUnion(pCharlist, pCharlist1);
char message[100];
sprintf(message, "charListUnion并集成功,长度为%d", unionList->len);
assertMessageMoreTest( unionList->len > 0, message , "charListUnion并集失败");
}
void test_charListIntersection_demo() {
CharList *pCharlist1 = charListCopy(pCharlist);
addCharList(pCharlist1, "12345");
addCharList(pCharlist1, "把231");
CharList *intersection = charListIntersection(pCharlist, pCharlist1);
char message[100];
sprintf(message, "charListIntersection交集成功,长度为%d", intersection->len);
assertMessageMoreTest( intersection->len > 0, message , "charListIntersection交集失败");
}
void test_CharListIterator_demo() {
CharListIterator *iterator = createCharListIterator(pCharlist);
while (hasNextCharListIterator(iterator)) {
char *str = nextCharListIterator(iterator);
printf("%s,", str);
}
char message[100];
sprintf(message, "CharListIterator迭代器创建成功");
assertMessageMoreTest( iterator!=NULL, message , "CharListIterator迭代器创建失败");
}
void test_charlist_demo_init_method() {
addTestMethodName(__FUNCTION__, "test_create_charlist_demo", TRUE, 0, test_create_charlist_demo);
addTestMethodName(__FUNCTION__, "test_add_charlist_demo", TRUE, 1, test_add_charlist_demo);
addTestMethodName(__FUNCTION__, "test_get_charlist_demo", TRUE, 2, test_get_charlist_demo);
addTestMethodName(__FUNCTION__, "test_del_charlist_demo", TRUE, 3, test_del_charlist_demo);
addTestMethodName(__FUNCTION__, "test_del_index_charlist_demo", TRUE, 4, test_del_index_charlist_demo);
addTestMethodName(__FUNCTION__, "test_forEachCharList_demo", TRUE, 5, test_forEachCharList_demo);
addTestMethodName(__FUNCTION__, "test_charListIndexOf_demo", TRUE, 6, test_charListIndexOf_demo);
addTestMethodName(__FUNCTION__, "test_charListLastIndexOf_demo", TRUE, 7, test_charListLastIndexOf_demo);
addTestMethodName(__FUNCTION__, "test_quickSortCharList_demo", TRUE, 8, test_quickSortCharList_demo);
addTestMethodName(__FUNCTION__, "test_charListIsSorted_demo", TRUE, 9, test_charListIsSorted_demo);
addTestMethodName(__FUNCTION__, "test_charListBinarySearch_demo", TRUE, 10, test_charListBinarySearch_demo);
addTestMethodName(__FUNCTION__, "test_charListSet_demo", TRUE, 11, test_charListSet_demo);
addTestMethodName(__FUNCTION__, "test_charListReverse_demo", TRUE, 12, test_charListReverse_demo);
addTestMethodName(__FUNCTION__, "test_charListCopy_demo", TRUE, 13, test_charListCopy_demo);
addTestMethodName(__FUNCTION__, "test_charListDistinct_demo", TRUE, 14, test_charListDistinct_demo);
addTestMethodName(__FUNCTION__, "test_charListMerge_demo", TRUE, 15, test_charListMerge_demo);
addTestMethodName(__FUNCTION__, "test_charListDifference_demo", TRUE, 16, test_charListDifference_demo);
addTestMethodName(__FUNCTION__, "test_charListComplement_demo", TRUE, 17, test_charListComplement_demo);
addTestMethodName(__FUNCTION__, "test_charListUnion_demo", TRUE, 18, test_charListUnion_demo);
addTestMethodName(__FUNCTION__, "test_charListIntersection_demo", TRUE, 19, test_charListIntersection_demo);
addTestMethodName(__FUNCTION__, "test_CharListIterator_demo", TRUE, 20, test_CharListIterator_demo);
addTestMethodName(__FUNCTION__, "test_print_charlist_demo", TRUE, 99, test_print_charlist_demo);
addTestMethodName(__FUNCTION__, "test_charListClean_demo", TRUE, 100, test_charListClean_demo);
}
验证
#include <stdio.h>
#include "unittest/testfactory.h"
#include "./unittest//testdemo/test_verification_demo.h"
#include "./unittest/testdemo/test_verification_demo1.h"
#include "./unittest/testdemo/test_charlist_demo.h"
static void test_init(){
//初始化测试组
addTestGroup("verification_demo_initMethod",FALSE,0,verification_demo_initMethod);
addTestGroup("verification_demo1_initMethod",FALSE,1,verification_demo1_initMethod);
addTestGroup("test_charlist_demo_init_method",TRUE,2,test_charlist_demo_init_method);
}
static void test_run(){
testMain(test_init);//初始化测试
//运行全部的测试方法
// test_Run_GroupAll_MethodAlL();
test_Run_Core_Group_ALL();//运行全部的测试组
// test_Run_Group("test_charlist_demo_init_method"); //运行指定测试组
// test_Run_Method("test_print_charlist_demo"); //运行指定测试方法
}
int main() {
test_run();
return (0);
}
现在我就能随心所欲的测试了,想测试那个方法就测试那个方法,方法之间还可以联动测试,模块和模块还可以交互测试,等等