Mock的基本概念和方法(续)

来源:互联网 发布:软件系统项目实施方案 编辑:程序博客网 时间:2024/04/25 13:12

本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一@小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!

Content

0.

1. 平台

2. 第三方库

3.如何使用CMockUnity

3.1 修改业务代码

3.2 编写单元测试

3.3如何Mock并测试?

(1)生成mock文件

(2)生成单元测试runner

(3)拷贝或修改生成的mock文件

(4) build

(5) 讨论

4. 总结

Reference

Appendix 1: Cmock installation

Appendix 2: Unity installation

Appendix 3: Ruby installation

Appendix 4: Mockyour_file.c

Appendix 5: my_business_runner.c

 

 

0.

 

Mock的基本概念和方法一文中,笔者在结尾提出了一个问题,有没有一种比较好的方法或者工具,能自动产生一些文件或者目录,供测试使用?

 

有,一定有,因为,这个世界从来不缺聪明的发明人。

 

那么,本文仍以Mock的基本概念和方法一文中的例子为例,重点讲述使用CmockUnity等工具进行单元测试的方法。

注:本文的实验,CUnit不是必须的。

 

 

1.平台

 

Cygwin, or Linux

 

工作目录:

Linux : # cd /usr/src/cmock_sample

Cygwin: $ cd /usr/src/cmock_sample

 

2.第三方库

 

本文实验用到的第三方库分别为:

 

cmock_2_0_204.zip:http://sourceforge.net/projects/cmock/files/cmock/cmock2.0/cmock_2_0_204.zip

unity_2_0_113.zip:http://sourceforge.net/projects/unity/files/unity/unity2.0/unity_2_0_113.zip

ruby-1.9-stable.tar.gz:http://ftp.ruby-lang.org/pub/ruby/ruby-1.9-stable.tar.gz

 

实际上,cmock_2_0_204.zip在其vendor目录中包含了Unity

 

3.如何使用CMockUnity

 

以下将以cygwin平台为例。

 

3.1修改业务代码

 

该例子中的业务代码文件:my_business.c

为例使用CMockUnity工具,需要修改my_business.c文件,将其中的main函数删除,并增加my_business.h文件。如下。

/*

 * my bussiness.h

 */

 

int read_file();

my_business.c文件内容。

/*

 * my bussiness

 */

 

#include "my_business.h"

#include

 

int read_file()

{

    FILE* fp = your_file_open("data.txt");

    //assert(fp != 0);

 

    /*

     * here my business start, for example, read data from the file.

     * for test, only print the fp.

     */

    printf("%s, %d: file handle = 0x%x/n", __FUNCTION__, __LINE__, (unsigned int)fp);

 

    your_file_close(fp);

    return 0;

}

注:实际上,或许某些场合不需要该头文件,但为了本文说明问题的需要,提供该文件。后面的Unity工具将根据该文件自动生成mock文件。

 

3.2编写单元测试

 

要对业务代码做单元测试,应该事先编写好单元测试代码,文件为my_business_unittest.c,如下。

/*

 * my bussiness unittest

 */

 

#include "my_business.h"

#include "unity.h"

 

void setUp(void)

{

}

 

void tearDown(void)

{

}

 

void test_read_file()

{

    TEST_ASSERT_EQUAL(0, read_file());

}

 

void test_read_file2()

{

    TEST_ASSERT_NOT_EQUAL(1, read_file());

}

3.3如何Mock并测试?

 

(1)生成mock文件

 

业务代码my_business.h/.c依赖your_file.h/.c,根据Cmock/Unity框架,要根据your_file.h自动生成mock文件。Cmock框架提供了该自动生成的功能,是用ruby写的scripts,在./cmock/lib目录下,在运行这些脚本时,使用ruby命令,因此需要第三方库ruby。完成该自动生成功能的脚本是./cmock/lib/cmock.rb,可以处理1个或多个.h文件。

$ mkdir mocks //默认情况下,生成的mock文件保存在该目录,故需事先建立好

$ ruby /usr/src/cmock/lib/cmock.rb your_file.h //运行该脚本生成mock文件

Creating mock for your_file...

$ cd mocks

$ ls

Mockyour_file.c Mockyour_file.h //自动生成的mock文件

$ cd ..

此处,笔者仅提供Mockyour_file.h的内容,Mockyour_file.c文件太大,请参考附录。

/* AUTOGENERATED FILE. DO NOT EDIT. */

#ifndef _MOCKYOUR_FILE_H

#define _MOCKYOUR_FILE_H

 

#include "your_file.h"

 

void Mockyour_file_Init(void);

void Mockyour_file_Destroy(void);

void Mockyour_file_Verify(void);

 

#define your_file_open_ExpectAndReturn(fname, cmock_retval) your_file_open_CMockExpectAndReturn(__LINE__, fname, cmock_retval)

void your_file_open_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, char* fname, FILE* cmock_to_return);

#define your_file_close_Expect(fp) your_file_close_CMockExpect(__LINE__, fp)

void your_file_close_CMockExpect(UNITY_LINE_TYPE cmock_line, FILE* fp);

 

#endif

(2)生成单元测试runner

 

Unity工具提供了根据单元测试文件自动生成runner文件的功能,该runner文件中包含main()函数,这就是单元测试程序启动的入口。这也是为什么要修改my_business.c,将其中的main()删除的原因。

 

What a great idea!Ruby真的是一门很好的语言,是时候学习了。

 

这将节省开发人员很多的时间,使开发人员将精力集中在单元测试本身和设计测试用例上。

$ ruby /usr/src/unity/auto/generate_test_runner.rb my_business_unittest.c my_business_runner.c

$ ls

data.txt  makefile my_business.c  my_business_runner.c   your_file.c

make.bat  mocks    my_business.h  my_business_unittest.c your_file.h

(3)拷贝或修改生成的mock文件

 

因为生成的mock文件放在mocks目录,且在Mockyour_file.h中包含了your_file.h,但mocks目录中并没有your_file.h文件,而是在上一级目录中,因此需要将其拷贝到上一级目录,或者修改Mockyour_file.h文件中包含your_file.h的路径。笔者选择拷贝。

$ cp mocks/Mockyour_file.h Mockyour_file.h

$ cp mocks/Mockyour_file.c Mockyour_file.c

自此,要进行单元测试所需的.h/.c文件全部建立,小结一下,看看有哪些文件。

 

你的代码文件:your_file.h/.c       (该文件在测试时不再使用)

mocked文件Mockyour_file.h/.c   (在测试时要依赖该文件)

业务代码文件:my_business.h/.c

业务测试文件:my_business_unittest.c

测试运行文件:my_business_runner.c (main()函数即在其中)

 

(4)build

 

本文的实验,笔者编写了makefile(Linux平台/Cygwin环境)或者make.bat(win32平台),让build更加快速和可控。

 

使用CMokcUnity进行单元测试和Mock,一定会依赖CMockUnity,因此这两个工具的源代码cmock.cunity.c也一定要编译到并链接到目标文件。那么对于CMockUnity,我们需要或者依赖哪些文件呢?

 

不要被CMockUnity的内容吓到!虽然其中有很多目录和文件,但其核心(框架)文件很少,而这些核心文件正是build需要的。

 

CMock: ./cmock/src/cmock.c //CMockcore文件在./cmock/src目录

       ./cmock/src/cmock.h

Unity: ./unity/src/unity.c //Unitycore文件在./unity/src目录

       ./unity/src/unity.h

       ./unity/src/unity_internals.h

 

综上,编写的makefile文件和make.bat文件如下。makefile文件适用于cygwinLinux平台。

CXX = gcc

CXXFLAGS += -g -Wall -Wextra

 

TESTS = my_business

 

CMOCK_DIR = /usr/src/cmock

CMOCK_SRC = $(CMOCK_DIR)/src

UNITY_DIR = /usr/src/unity

UNITY_SRC = $(UNITY_DIR)/src

 

ifeq ($(OS), Windows_NT)

TARGET_EXTENSION=.exe

else

TARGET_EXTENSION=.out

endif

 

TARGET = $(TESTS)$(TARGET_EXTENSION)

 

CLEANUP = rm -f $(TARGET) *.o

 

all : $(TARGET)

 

clean :

$(CLEANUP)

 

unity.o: $(UNITY_SRC)/unity.c

$(CXX) $(CXXFLAGS) -I$(UNITY_SRC) -c $^

 

cmock.o: $(CMOCK_SRC)/cmock.c

$(CXX) $(CXXFLAGS) -I$(CMOCK_SRC) -I$(UNITY_SRC) -c $^

 

mockyour_file.o: mockyour_file.c

$(CXX) $(CXXFLAGS) -I$(CMOCK_SRC) -I$(UNITY_SRC) -c $^

 

my_business.o: my_business.c

$(CXX) $(CXXFLAGS) -c $^

 

my_business_unittest.o: my_business_unittest.c

$(CXX) $(CXXFLAGS) -I$(UNITY_SRC) -c $^

 

my_business_runner.o: my_business_runner.c

$(CXX) $(CXXFLAGS) -I$(UNITY_SRC) -c $^

 

$(TARGET): unity.o cmock.o mockyour_file.o my_business.o my_business_unittest.o my_business_runner.o

$(CXX) $(CXXFLAGS) $^ -o $@

(5)讨论

 

这真的是一种前无古人的方法,CMock能自动生成mock文件,让你进行单元测试;Unity能自动生成单元测试runner,让你的单元测试跑起来。CMockUnity的出现,为广大开发者节省了宝贵的时间,使你的精力集中于单元测试本身和测试用例的设计上。

 

4.总结

 

本文,笔者以一个例子讨论了使用CMockUnity进行mock和单元测试的方法和过程,主要关注如何使用这两个工具并buildbuild时,要注意CMockUnitycmock.cunity.c也要编译并链接到目标文件。

本文重点如下。

  • 生成mock文件
  • 生成单元测试runner
  • build

 

广大软件开发者们,如果要做C项目的单元测试,尤其是嵌入式软件的单元测试,那就去大胆尝试CMockUnity吧!

 

 

Reference

 

CMock简介:CMock Summary.pdf

Unity简介:Unity Summary.pdf

CMock设计原理:Functionality_and_Design_of_the_CMock_Framework.pdf

如何mocking嵌入式软件:Mocking the Embedded World - Test-Driven Development, Continuous Integration, and Design Patterns.pdf

 

http://sourceforge.net/apps/trac/cmock

http://sourceforge.net/apps/trac/unity

http://sourceforge.net/projects/unity/forums/forum/770030/topic/4067272

http://sourceforge.net/projects/unity/forums/forum/770030/topic/3795145

http://sourceforge.net/apps/trac/cmock/wiki/EclipseIde

http://sourceforge.net/apps/mediawiki/unity/index.php?title=Eclipse_IDE_Integration

http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks (各种单元测试工具比较)

http://sourceforge.net/projects/unity/forums/forum/770030/topic/4067272 (CmockUnity的关系)

http://meekrosoft.wordpress.com/2010/01/29/unit-test-embedded-software-in-3-easy-steps (嵌入式软件单元测试的3个步骤)

 

http://www.lulu.com/product/paperback/embedded-testing-with-unity-and-cmock/14408590?productTrackingContext=search_results/search_shelf/center/1, By Mark VanderVoord.

 

 

Appendix 1: Cmock installation

 

# cd /usr/src

# wget http://sourceforge.net/projects/cmock/files/cmock/cmock2.0/cmock_2_0_204.zip

# unzip -x cmock_2_0_204.zip

# cd cmock

编译需要ruby的构建系统rake,有待研究。

 

Appendix 2: Unity installation

 

# cd /usr/src

# wget http://sourceforge.net/projects/unity/files/unity/unity2.0/unity_2_0_113.zip

# unzip -x unity_2_0_113.zip

# cd unity

# make

# cd examples

# make

 

Appendix 3: Ruby installation

 

$ cd /usr/src

$ wget http://ftp.ruby-lang.org/pub/ruby/ruby-1.9-stable.tar.gz

$ tar.exe  -zxvf ruby-1.9-stable.tar.gz

$ cd ruby-1.9.2-p180

$ ./configure && make && make install

 

Appendix 4: Mockyour_file.c

 

Appendix 5: my_business_runner.c



Technorati 标签: 单元测试;Mock;CMock;Unity

原创粉丝点击