I have a C++ project in Visual Studio, and have added another project exclusively for testing. Both of these projects are EXEs (console apps). So how do I use the first project inside the second?
Just to clarify, the question here would be somewhat self-evident if the first project was a library that one could simply include in the second project but, being an EXE, this is where the problem lies.
Independent and Repeatable: Googletest isolates the tests by running each of them on a different object. Portable and Reusable: Googletest works on different Oses (Linux, Windows, or a Mac), with different compilers. When tests fail, it should provide as much information about the problem as possible.
Per your comments, you have a C++ console application (MyApp)
for which you have developed some application-specific classes that you want to unit-test with googletest in
Visual Studio. How?
As you say, if you wanted to unit-test a library the way to do it would be obvious. You would:
UnitTest
). UnitTest
project dependent on the library project, so that building UnitTest
ensures MyApp
is up-to-date.UnitTest
app per googletest docs.But since the classes you want to unit-test are specific to MyApp
, you don't have any
library.
A drill-sergeant answer to that is: You don't have a library containing the classes you want to unit-test? So make one!
That way you use 3 projects:-
MyAppLib
, generating library that contains all the functionality you want to unit-test.MyApp
, generating the same executable as at present, but linking MyAppLib
UnitTest
, generating an executable that unit-tests MyAppLib
, also linking MyAppLib
However if you don't like the drill-sergeant answer you can work around it.
From the usual build-system point of view (the one designed into Visual Studio),
the important output of the MyApp
project is the build-target - the .exe
.
The .obj
files generated are just intermediate by-products. VS offers you no support
for treating these by-products as automatic linker inputs of a dependent project, and if a dependent project was also an .exe
of the same sort - as it is your case - then such automatic linkage would be impossible anyhow because the main entry point would be multiply defined.
But from the unit-testing point of view it's the other way round. The .exe
is of no interest, whereas (some of) the .obj
files wholly or partly contain the implementations of the classes you want to unit test. In the text-book case where class foo
is defined in foo.h
and implemented in foo.cpp
, the object file foo.obj
is needed in the linkage of UnitTest
.
For simplicity, assume that MyApp
employs just one application-specific class foo
,
defined in foo.h
and implemented in foo.cpp
. Then you have two options for building UnitTest
.
a) You can add foo.cpp
to the source files of UnitTest
. Don't copy it of course. Just Add an existing item from the source folder of MyApp
. Then you're done, but this
course has the downside that foo.cpp
is exposed to untoward editing within
the UnitTest
project.
b) You can treat foo.obj
just like a static library required for the linkage of UnitTest
and follow steps 1) - 6) above. This means in particular at step 3) that the {Debug|Release} build of UnitTest
is configured with library-search directories that include \path\to\MyApp\{Debug|Release}
(either in relative or absolute form).
In reality, for option b), there's very likely more than one .obj
file from MyApp
that you will have to link in UnitTest
, and quite likely that their number will grow with time. Maintaining the right linkage of UnitTest
could become a chore, and you might come to the conclusion that the drill-sergeant was right after all.
Depends. Google Test is (primarily) a Unit Testing framework (oversimplifying, testing classes). You can absolutely use is for other types of tests, but it doesn't have "built in" functionality for other types of testing, you'll have to write it yourself.
If you are trying to system test your executable, than you can run the process. I suggest using Boost.Process if you are using a multi-platform system or already have a boost dependency. Else, look here: launch an exe/process with stdin stdout and stderr?
The "tests" you write will call the executable, and can input stdin or stdout accordingly.
For example:
std::string path_to_exectuable = "thepath";
TEST(FooTester,CheckHelpScriptReturns0)
{
using bp =::boost::process;
std::vector<std::string> args; args.push_back("--help");
bp::context ctx;
ctx.stdout_behavior = bp::capture_stream();
bp::child c = bp::launch(exec, args, ctx);
bp::status s = c.wait();
ASSERT_TRUE(s.exited())<<"process didn't exit!";
ASSERT_EQ(s.exit_status(),0)<<"Help didn't return 0";
}
I was in a similar situation and I set this up in a way that effectively accomplishes the same goal of Mike Kinghan's answer as far as the compiler is concerned, but goes about it a different way from the user's perspective.
What I did was create a custom Configuration that I called "Testing". You create a new configuration by opening the project settings, choosing "Configuration Manager..." and selecting "New..." in the configuration selection box.
When prompted, I chose to copy the settings from the default "Debug" configuration, so that I can use the debugger with my tests just the same as if I was in the "Debug" configuration.
Under the new Testing configuration, I set the options for the compiler and linker to use google test as you normally would.
The important change in the properties is that I define a preprocessor variable which I have called "TESTING".
I rewrote my "main.cpp" to look something like this:
...
// includes
// functions
// whatever
...
#ifdef TESTING
#include <gtest/gtest.h>
#endif
int main(int argc, char **argv) {
#ifdef TESTING
::testing::InitGoogleTest(&argc, argv);
int val = RUN_ALL_TESTS();
getchar(); // not necessary, but keeps the console open
return val;
#endif
// rest of main() as normal...
}
What I'm trying to indicate is that I only changed a few lines right around where main
is defined, I don't have to make gross changes spread throughout the file.
Now that this is all set up I simply made a new source folder for my tests, and create ".cpp" files in there. To avoid bloating the normal executable, I wrap these files with a check for the TESTING variable, so I have something like this:
tests/Test.cpp:
#ifdef TESTING
#include <gtest/gtest.h>
#include "my_class_header.h"
TEST(TestMyClass, test_something) {
// perform some test on class
}
#endif
I think these files still get "hit" by the compiler under Debug and Release configurations, so having a ton of these might slow down the build, but the Debug and Release objects wont get bloated with testing code.
The two takeaways are:
.obj
files yourself can become a chore, but by using this method, the default Visual Studio settings manage this for you.One downside is that effectively redundant copies of all object files will get created in the "Testing" output directory. With more configuration, surely there must be a way to "share" the Debug object files, but I didn't have a reason to go that far.
This is a very simple method which may be a lot easier than refactoring your application into separate libraries and a main. I don't love using preprocessor wankery, but in this case it's fairly straightforward, not too much code bloat, and accomplishes exactly what it needs to. You could always trigger the tests another way, without using the preprocessor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With