I have a basic question regarding Googletest in Eclipse.
I am using the test-runner plug in to run the Googletests.
But I need to specify a binary which runs my unit tests (of course that makes sense.)
The problem is that in my project I now have two main functions, one to run the actual program and one
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
to run the google tests.
Each time I want to run one I comment the other out, which of course is stupid.
But what practice do you use to handle this situation?
Googletest C++ is a unit-testing framework. That means it is intended for testing
implementations of C++ APIs. It isn't intended for testing programs.
For practical purposes a C++ API is what you get in a C++ header file. The
implementation of such an an API might be:
- Just the header file itself. (The implementation is entirely inline)
- The header file plus a single C++ source file
- The header file plus a bunch of C++ source files
To generalize, the implementation of a C++ API is a header file plus
0 or more source files.
Say your program my_prog
invokes an API that you or your team have developed
for managing gizmos. The implementation is something like:
gizmo.h
[gizmo_0.cpp,...gizmo_N.cpp]
where [...]
means optionally ...
Maybe my_prog
relies on other APIs for which you or your team are responsible,
but we'll stick with just one. my_prog
uses the gizmo API by:-
- Using
#include "gizmo.h"
in some source files.
- Compiling the
[gizmo_0.cpp,...gizmo_N.cpp]
source files, if any.
- Linking the
[gizmo_0.o,...gizmo_N.o]
object files, if any.
(gizmo_0.obj
, etc. if you're on Windows)
Testing your implementation of the gizmo API with Googletest is supposed
to confirm that this implementation is correct, independently of my_prog
or any other program that relies on it to manage gizmos. So incorporating
the unit-testing of the implementation in the implementation of my_prog
is misguided:-
Maybe your colleague writes another program that also needs to manage gizmos
with this implementation. Maybe you write another one. Is whoever writes this
other program supposed to repeat the process of incorporating gizmo unit-tests
into it - The same ones? Different ones? - and making the program conditionally
compile as either a gizmo test-harness or as whatever it's supposed to be in real life?
And how do you know that the gizmo implementation isn't somehow entangled with
functionality that's unique to my_prog
, or with the implementation of some
other API that my_prog
uses in the same way - so that when you or somebody
else tries to reuse it in another program, it breaks or behaves wrongly?
No program that relies on this gizmo implementation is the place to put
its unit-testing. Making my_prog
conditionally compile different main
functions so it can
double as a unit-test harness for your gizmo library is similar to cutting a hole in the
crotch of your jeans for your head to fit through.
The way you're supposed to unit-test the gizmo library is to write a program that is the
test-harness for this library, and nothing else. This program, say gizmo_test
, will
use the gizmo API in just the same way as any other program would use it, but
for the sole purpose of testing the gizmo library. All that gizmo_test
will do is execute tests
of the gizmo library, by invoking its API.
As a first approximation, the GoogleTest recipe for gizmo_test
is:
Write a header file, gizmo_test.h
#include "gizmo.h"
in it
#include <gtest/gtest.h>
in it
Then write your Googletest test cases in it
Write the following source file gizmo_test.cpp
#include "gizmo_test.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Create a project gizmo_test
- in Eclipse or whatever development environment or build system you use -
that builds the gizmo_test
executable by:
- Compiling the source files
gizmo_test.cpp
+ [gizmo_0.cpp,...gizmo_N.cpp]
- Linking the resulting object files
gizmo_test.o
+ [gizmo_0.o,...gizmo_N.o]
, plus libgtest
and any other libraries on which your gizmo library depends
You have two projects. The one that makes my_prog
and the one that makes gizmo_test
. In your development environment or
build system, make the build of my_prog
depend on the build of gizmo_test
, so that when you change anything that affects
the gizmo library and rebuild my_prog
, gizmo_test
gets rebuilt first.
That's a first approximation. Did you notice a while back that I started talking about your gizmo library? That's what
you've got (or should have). In C++ and programming generally, the implementation of an an API is called a library.
And maybe you also noticed some fragility, inconvenience and wastage in the recipe for gizmo_test
. You have the same set of gizmo source files
[gizmo_0.cpp,...gizmo_N.cpp]
in both projects. So you might edit, compile and link them differently in two projects. And they'll get compiled in both projects, either differently,
which is wrong, or identically, which is pointless.
Of course if this set of source files is empty - the gizmo library is nothing but gizmo.h
- there's no such problem. But if it's not empty,
there is.
As you know, in C++ we don't use a library by building its source files in every program that uses it - not unless it's a header-only library.
A library is built by itself into an object library (either static or dynamic), and to use it a program just includes the library's
header file(s) and links the object library.
That's how a program should use your gizmo library too. So to the final approximation:-
- Make a project
libgizmo
that builds a gizmo object library (static or dynamic, as you see fit).
- Make a project
gizmo_test
as above, except that instead of compiling and linking [gizmo_0.cpp,...gizmo_N.cpp]
, it just links libgizmo
, and make this project
depend on the libgizmo
project.
- Make a project
my_prog
as you have it now, but instead of compiling and linking [gizmo_0.cpp,...gizmo_N.cpp]
, just link libgizmo
, and make this project
depend on the gizmo_test
project.
So you have three projects by the time you build the first program that uses the gizmo library. Each subsequent program that uses the gizmo library needs one
more project, like the my_prog
project.
Googletest is designed for testing C++ libraries, and this is how you're supposed to use it.
Now I know nothing about your program or how you are currently deploying Googletest test cases in your project. Maybe there aren't any well-defined API implementations in it
that those test cases are supposed to exercise, that you can factor out into free-standing libraries. Possibly that could be because your program is so very simple that
unit-testing its "components" is non-applicable, and you'd be wiser just to write blackbox tests of the program. More likely it would be because you've so far failed
to design a program architecture that is capable of being unit-tested. If that's what you find, you need to fix it, and then apply Googletest the right way. It will be worth the
effort.
And in case it needs pointed out, unit-tests are not program tests, so as well as unit-testing any libraries your program relies on, if they are your responsibility, you also need blackbox tests of your program.