2

I have a C module and I want to refactor a little bit. There are some global variables and structures which are not hidden (in the module.h file). I use this variables in some test case but nowhere else so I thought it's a good idea to set them to static. In my test cases I extern these variables and fill with test values. But if they will be static variables I can't reach them from the test case. I don't want to write getter and setter methods and put it to the .h file, because I want to hide this variables.

I know if I include the .c file into my test case I can see the static variables. Is there any other way to fill these variables?

I use cygwin and gcc, the test framework is CppUtest.

Thanks in advance.

hcpeter
  • 614
  • 3
  • 11
  • 24

2 Answers2

2

There are two main possibilities:

  1. The difficulty of testing is showing that the interface provided by the module is incomplete.
  2. Your unit testing is prying into the internals of the module in a way that consumers would never need to do.

If the problem is an incomplete interface, then you can add the extra interfaces that make the module more easily testable, and more generally usable. For example, if the static variables are counters of some sort, you might need to add a 'reset' method to set the counters back to zero, ready for the next part of the unit testing, or (in the more general use case) to allow the statistics to be zeroed so that you can accumulate the statistics afresh.

If the problem is unit testing needing to probe more deeply than consumers need to probe, then I don't see anything wrong with the test code using #include "sourcecode.c". It keeps the module code clean for general use; it allows the unit test to probe more deeply than it would otherwise. It converts the test code from 'black box' testing to a form of 'white box' testing - the test can see more of the tested code than a regular black box test can. But that's sometimes helpful. It is often an intermediate stage during development. Once you have all the black box testing in place, you may not need to be concerned with probing the internals in the same way - until you make changes.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I think in my case the intarface isn't incomplete. I'm inclined to include the whole c file to my test case. Technically it means they are in the same compilation unit, so the test case can see the static variables. But to be honest: I don't like the idea. It looks like a workaround. Is there any solution which I didn't notice? – hcpeter Nov 24 '11 at 21:13
  • No; that's why I outlined the two possibilities. If the interface is incomplete, I recommend completing it. For example, I am working on some locale-related formatting code. The simpler functions use the 'current locale', but testing that would be a complete bitch. I've completed the interface by providing generic functions which take a 'locale' as an argument, and the most easily used functions (without the locale) simply find the current locale and then call the generic functions. I can test the generic functions with all sorts of oddball locales in ways which were not possible otherwise. – Jonathan Leffler Nov 24 '11 at 21:26
  • Thanks Jonathan I realized that is a viable option. So I included the whole c file and gave init value to the static variables. I can test the module now. – hcpeter Nov 26 '11 at 20:18
  • 1
    See also [How to test a static function?](http://stackoverflow.com/questions/593414/). – Jonathan Leffler Jun 07 '15 at 02:17
0

Often its a good idea to create these static variables in a separate file (some like to call it scaffolding) so that you can get away from including the .c. The basic theory behind this is that if you are always including .c files it quickly becomes impossible to unit test since the whole idea of unit testing is drilling down and testing one bit of code without depending on the rest of it. Once you're including all these exterior .c files, you aren't doing this.

dbeer
  • 6,963
  • 3
  • 31
  • 47
  • Thanks for the advice, it sounds better than I include the whole c file to the test case. But... I came from java and jUnit, and a little bit difficult to switch the c approach (-: – hcpeter Nov 23 '11 at 17:16
  • Java does make unit testing easier. I loved how you could have a main method in each file. Oh well, I like C anyway. – dbeer Nov 23 '11 at 17:49
  • @dbeer, can you expand on this a bit? I'm confused how this resolves the access problem - wouldn't the original c file still have to #include the separate scaffolding file, for the access to remain truly static? Would you swap out the scaffold file in the test compilation (e.g. add the test scaffold before the true scaffold in the include path) and then leave the declarations non-static in the test scaffold? I'm considering just using an `#ifdef` e.g. with `CPPUTEST_STATIC` defined as either `static` or empty, which seems to be simpler, less duplication (but pollutes the source a bit more)... – johnny Nov 23 '20 at 17:05