单元测试 c 代码[关闭]

I worked on an embedded system this summer written in straight C. It was an existing project that the company I work for had taken over. I have become quite accustomed to writing unit tests in Java using JUnit but was at a loss as to the best way to write unit tests for existing code (which needed refactoring) as well as new code added to the system.

Is there any way to make unit testing plain C code as easy as unit testing Java code with, for example, JUnit? Any insight that would apply specifically to embedded development (cross-compiling to arm-linux platform) would be greatly appreciated.

转载于:https://stackoverflow.com/questions/65820/unit-testing-c-code

csdnceshi63
elliott.david my bad, I thought it would be better suited there. So I guess they're doomed to be off-topic, even if sometimes interesting, wherever they get posted
3 年多之前 回复
csdnceshi52
妄徒之命 library recommendations are blatantly off-topic over there for the same reasons as here. Please abstain of recommending sites you're not familiar with. See What goes on Software Engineering (previously known as Programmers)? A guide for Stack Overflow
3 年多之前 回复
csdnceshi68
local-host so is there any other SE website where you can ask the type of questions that you just described ( a general question asking for a lib to do a task etc)
3 年多之前 回复
csdnceshi51
旧行李 Take a look at cmocka.org
大约 5 年之前 回复

29个回答

One unit testing framework in C is Check; a list of unit testing frameworks in C can be found here and is reproduced below. Depending on how many standard library functions your runtime has, you may or not be able to use one of those.

AceUnit

AceUnit (Advanced C and Embedded Unit) bills itself as a comfortable C code unit test framework. It tries to mimick JUnit 4.x and includes reflection-like capabilities. AceUnit can be used in resource constraint environments, e.g. embedded software development, and importantly it runs fine in environments where you cannot include a single standard header file and cannot invoke a single standard C function from the ANSI / ISO C libraries. It also has a Windows port. It does not use forks to trap signals, although the authors have expressed interest in adding such a feature. See the AceUnit homepage.

GNU Autounit

Much along the same lines as Check, including forking to run unit tests in a separate address space (in fact, the original author of Check borrowed the idea from GNU Autounit). GNU Autounit uses GLib extensively, which means that linking and such need special options, but this may not be a big problem to you, especially if you are already using GTK or GLib. See the GNU Autounit homepage.

cUnit

Also uses GLib, but does not fork to protect the address space of unit tests.

CUnit

Standard C, with plans for a Win32 GUI implementation. Does not currently fork or otherwise protect the address space of unit tests. In early development. See the CUnit homepage.

CuTest

A simple framework with just one .c and one .h file that you drop into your source tree. See the CuTest homepage.

CppUnit

The premier unit testing framework for C++; you can also use it to test C code. It is stable, actively developed, and has a GUI interface. The primary reasons not to use CppUnit for C are first that it is quite big, and second you have to write your tests in C++, which means you need a C++ compiler. If these don’t sound like concerns, it is definitely worth considering, along with other C++ unit testing frameworks. See the CppUnit homepage.

embUnit

embUnit (Embedded Unit) is another unit test framework for embedded systems. This one appears to be superseded by AceUnit. Embedded Unit homepage.

MinUnit

A minimal set of macros and that’s it! The point is to show how easy it is to unit test your code. See the MinUnit homepage.

CUnit for Mr. Ando

A CUnit implementation that is fairly new, and apparently still in early development. See the CUnit for Mr. Ando homepage.

This list was last updated in March 2008.

Others:

CMocka

CMocka is a test framework for C with support for mock objects. It's easy to use and setup. CMocka official homepage.

Criterion

Criterion is a cross-platform C unit testing framework supporting automatic test registration, parameterized tests, theories, and that can output to multiple formats, including TAP and JUnit XML. Each test is run in its own process, so signals and crashes can be reported or tested if needed. See the Criterion homepage for more information.

HWUT

HWUT is a general Unit Test tool with great support for C. It can help to create Makefiles, generate massive test cases coded in minimal 'iteration tables', walk along state machines, generate C-stubs and more. The general approach is pretty unique: Verdicts are based on 'good stdout/bad stdout'. The comparison function, though, is flexible. Thus, any type of script may be used for checking. It may be applied to any language that can produce standard output. See HWUT homepage.

Wikipedia gives a detailed list of C unit testing frameworks under List of unit testing frameworks: C

csdnceshi75
衫裤跑路 According to Check's Github Page, the latest version is 0.11.0 released on Dec 17, 2016.
3 年多之前 回复
csdnceshi80
胖鸭 cmocka is cool
接近 5 年之前 回复
csdnceshi61
derek5. I use HWUT at work and it works very well
接近 5 年之前 回复
csdnceshi58
Didn"t forge HWUT does generate remote-controllable stubs which comes pretty handy if you want to write tests for modules that interact with hardward drivers. Those drivers are, in most cases not present on a PC. HWUT Documentation
接近 5 年之前 回复
weixin_41568184
叼花硬汉 The one in Ubuntu dates from 2002. The most current version is from this year (2014 as of this comment). I had to compile it from source.
6 年多之前 回复
csdnceshi55
~Onlooker It seems like CUnit has more activity. The version of Check that came in the Ubuntu repo for 12.04 is buggy.
7 年多之前 回复
csdnceshi56
lrony* they do.
8 年多之前 回复
weixin_41568174
from.. Do people still use Check?
8 年多之前 回复
csdnceshi70
笑故挽风 +1 for Check. I have used it in several projects in which the largest parts of actual functionality was implemented as a library.
大约 11 年之前 回复
csdnceshi51
旧行李 the "here" link is broken and I think that this is the new link: check.sourceforge.net/doc/check.html/check_3.html#SEC3
11 年多之前 回复
csdnceshi50
三生石@ We use check for unit testing code on our embedded systems. For the most part check was a good choice but now we are working on systems running on uClinux and since check requires fork it doesn't work on those systems. :/
接近 12 年之前 回复
weixin_41568110
七度&光 Initially, Check looks very solid. I will have to see how it holds up under the fire of real use... but it definitely looks like it may fit the bill.
大约 12 年之前 回复

Personally I like the Google Test framework.

The real difficulty in testing C code is breaking the dependencies on external modules so you can isolate code in units. This can be especially problematic when you are trying to get tests around legacy code. In this case I often find myself using the linker to use stubs functions in tests.

This is what people are referring to when they talk about "seams". In C your only option really is to use the pre-processor or the linker to mock out your dependencies.

A typical test suite in one of my C projects might look like this:

#include "myimplementationfile.c"
#include <gtest/gtest.h>

// Mock out external dependency on mylogger.o
void Logger_log(...){}

TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}

Note that you are actually including the C file and not the header file. This gives the advantage of access to all the static data members. Here I mock out my logger (which might be in logger.o and give an empty implementation. This means that the test file compiles and links independently from the rest of the code base and executes in isolation.

As for cross-compiling the code, for this to work you need good facilities on the target. I have done this with googletest cross compiled to Linux on a PowerPC architecture. This makes sense because there you have a full shell and os to gather your results. For less rich environments (which I classify as anything without a full OS) you should just build and run on the host. You should do this anyway so you can run the tests automatically as part of the build.

I find testing C++ code is generally much easier due to the fact that OO code is in general much less coupled than procedural (of course this depends a lot on coding style). Also in C++ you can use tricks like dependency injection and method overriding to get seams into code that is otherwise encapsulated.

Michael Feathers has an excellent book about testing legacy code. In one chapter he covers techniques for dealing with non-OO code which I highly recommend.

Edit: I've written a blog post about unit testing procedural code, with source available on GitHub.

Edit: There is a new book coming out from the Pragmatic Programmers that specifically addresses unit testing C code which I highly recommend.

csdnceshi66
必承其重 | 欲带皇冠 I disagree. I found the book to be very valuable, especially for someone who is not real strong in C.
4 年多之前 回复
weixin_41568208
北城已荒凉 in essence I agree, what I show here is a preprocessor seam without wrapping the C include in an extern C. Regardless of that I found C++ quite handy as a test description language in practice. I have also written a C based framework for testing so I'm not dogmatic about this :-) github.com/meekrosoft/fff
接近 6 年之前 回复
csdnceshi57
perhaps? I know C and C++ has a lot of overlap, but it doesn't strike me as a good idea to use a C++ testing library when you're producing code that will be ultimately compiled in a C compiler.
接近 6 年之前 回复
csdnceshi74
7*4 Don't buy the prag. prog book. It doesn't contain any insights that are not in the answers to this question.
接近 8 年之前 回复
weixin_41568131
10.24 Not C, but C++.
接近 9 年之前 回复

Minunit is an incredibly simple unit testing framework. I'm using it to unit test c microcontroller code for avr.

csdnceshi69
YaoRaoLov This is pretty close to what I came up with before I started searching here! I would like to automate the testing so that TEST(funcname, body) creates the function and stores a pointer to the function, but it looks like I'll need to to some external processing.
3 年多之前 回复
weixin_41568196
撒拉嘿哟木头 I've made this into a github gist: gist.github.com/sam159/0849461161e86249f849
大约 6 年之前 回复
csdnceshi53
Lotus@ A little more advanced version can be found here
接近 7 年之前 回复
csdnceshi77
狐狸.fox I write small c programs and this is perfect
接近 7 年之前 回复
weixin_41568184
叼花硬汉 3 lines! Good grief ^_^
接近 8 年之前 回复
csdnceshi58
Didn"t forge I have no experience in doing embedded systems so I cannot comment on that, but for small C programs (schoolwork, scripts) this looks perfect. Great link.
9 年多之前 回复

If you are familiar with JUnit then I recommend CppUnit. http://cppunit.sourceforge.net/cppunit-wiki

That is assuming you have c++ compiler to do the unit tests. if not then I have to agree with Adam Rosenfield that check is what you want.

csdnceshi67
bug^君 I do the same thing. We have a utilities library written in C that we use underneath our C++ code and scripting languages. We use CppUnit for the tests and it's working out pretty well since we can use the same framework for both C and C++.
接近 10 年之前 回复
weixin_41568208
北城已荒凉 No, but C++ can interface to C libraries. So it may in fact be perfectly fine to test C libraries using a C++ unit test framework. (My company does that very thing by the way and it's so much easier than using C unit test frameworks.)
大约 12 年之前 回复
csdnceshi57
perhaps? The question is about C, not C++
大约 12 年之前 回复

There is CUnit

And Embedded Unit is unit testing framework for Embedded C System. Its design was copied from JUnit and CUnit and more, and then adapted somewhat for Embedded C System. Embedded Unit does not require std C libs. All objects are allocated to const area.

And Tessy automates the unit testing of embedded software.

csdnceshi63
elliott.david E.g. see a bug report I submitted, as well as another bug report that is unactioned for 3 years.
大约 10 年之前 回复
csdnceshi63
elliott.david I tried embunit and was disappointed by it.
大约 10 年之前 回复

I don't use a framework, I just use autotools "check" target support. Implement a "main" and use assert(s).

My test dir Makefile.am(s) look like:

check_PROGRAMS = test_oe_amqp

test_oe_amqp_SOURCES = test_oe_amqp.c
test_oe_amqp_LDADD = -L$(top_builddir)/components/common -loecommon
test_oe_amqp_CFLAGS = -I$(top_srcdir)/components/common -static

TESTS = test_oe_amqp
csdnceshi59
ℙℕℤℝ We are not using autotools (though it would be nice to move over at some point). Historically, I have used the main method for testing purposes and it is not a bad solution.
大约 12 年之前 回复

One technique to use is to develop the unit test code with a C++ xUnit framework (and C++ compiler), while maintaining the source for the target system as C modules.

Make sure you regularly compile your C source under your cross-compiler, automatically with your unit tests if possible.

weixin_41568127
?yb? Some documentation would be helpful. Project background and goals, a features list, advantages over existing alternatives, etc would be helpful for people who are checking it out for the first time.
接近 10 年之前 回复

LibU (http://koanlogic.com/libu) has an unit test module that allows explicit test suite/case dependencies, test isolation, parallel execution and a customizable report formatter (default formats are xml and txt).

The library is BSD licensed and contains many other useful modules - networking, debugging, commonly used data structures, configuration, etc. - should you need them in your projects ...

I'm currently using the CuTest unit test framework:

http://cutest.sourceforge.net/

It's ideal for embedded systems as it's very lightweight and simple. I had no problems getting it to work on the target platform as well as on the desktop. In addition to writing the unit tests, all that's required is:

  • a header file included wherever you're calling the CuTest routines
  • a single additional 'C' file to be compiled/linked into the image
  • some simple code added to to main to set up and call the unit tests - I just have this in a special main() function that gets compiled if UNITTEST is defined during the build.

The system needs to support a heap and some stdio functionality (which not all embedded systems have). But the code is simple enough that you could probably work in alternatives to those requirements if your platform doesn't have them.

With some judicious use of extern "C"{} blocks it also supports testing C++ just fine.

csdnceshi80
胖鸭 CuTest has worked well for me to test code running on a QNX system.
大约 9 年之前 回复
weixin_41568183
零零乙 I'll third this. I downloaded it when it was version 1.4 and modified it to dump to XML. It looks like there's a version 1.5 that I'll have to download and look at.
9 年多之前 回复
csdnceshi67
bug^君 I'll second the vote for CuTest. I've been using it for developing homebrew on the Nintendo DS and haven't had any difficulty getting it set up or using it.
11 年多之前 回复
共29条数据 1 3 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐