How will the first test be used?
So far, we have a single test that outputs its name when run, and this test is declared inside of main.cpp
. This is not how you’ll want to declare your tests going forward. I’ve mentioned having multiple .cpp
files with multiple tests in each one. We’re not ready for that yet but we can at least move the single test that we have into its own .cpp
file.
The whole point of declaring multiple tests in multiple .cpp
files is to help organize your tests. Group them into something meaningful. We’ll get to multiple tests later. For now, what is the purpose of our single test?
It is supposed to show that a test can be created. There may be other aspects of test creation that we’ll be interested in. So, it might make sense to create a .cpp
file focused on test creation. Inside this .cpp
file would be all the tests relating to different ways to create tests.
You can organize your tests however you want. If you have a project you are working on that has its own set of source files, it might make sense to group your tests around the source files. So, you would have a test .cpp
file with many tests inside, which are all designed to test everything related to a .cpp
file from your actual project. This would make sense if your project files were already organized well.
Or, you might take a more functional approach to organizing your tests. Since we only have a single header file called Test.h
that we need to test, instead of also creating a single .cpp
file to hold all the tests, let’s take a functional approach and split the tests based on their purpose.
Let’s add a new .cpp
file to the project called Creation.cpp
and move the single test that we have so far into the new file. At the same time, let’s think for a moment about how we will use the test library later on.
What we’re building is not really a library that gets compiled and linked into another project. It’s just a single header file called Test.h
, which other projects can include. It’s still a library, just one that gets compiled alongside the other project.
We can even start treating the tests we have now this way. In the project structure, we have Test.h
and main.cpp
so far. The main.cpp
file is similar to that of the test project that is intended to test the Test.h
include file. Let’s reorganize the project structure so that both main.cpp
and the new Creation.cpp
files are in a folder called tests
. These will form the basis for a testing executable that exercises all the tests needed to test Test.h
. In other words, we’re turning the console project that we have into a test project designed to test the test library. The test library is not a separate project because it’s just a single header file that will be included as part of other projects.
Later on, in other projects of your own, you can do the same thing. You’ll have your primary project with all its source files. You’ll also have another test project in a subfolder called tests
with its own main.cpp
and all the test files. Your test project will include Test.h
from the test library but it won’t be trying to test the test library as we’re doing here. It will instead be focused on testing your own project in the primary project folder. You’ll see how all this works once we get the test library to a suitable state so that it can be used to create a different project. We’ll be creating a logging library in Part 2, Logging Library. The logging library will have a subfolder called tests
, as I just described.
Turning back to what we have now, let’s reorganize the overall project structure for the test library. You can create the tests
folder and move main.cpp
into it. Make sure to place the new Creation.cpp
file into the tests
folder. The project structure should look like this:
MereTDD project root folder
Test.h
tests folder
main.cpp
Creation.cpp
The main.cpp
file can be simplified like this by removing the test and leaving only main
:
#include "../Test.h"
int main ()
{
MereTDD::runTests();
return 0;
}
Now, the new Creation.cpp
file only contains the single test we have so far, like so:
#include "../Test.h"
#include <iostream>
TEST
{
std::cout << mName << std::endl;
}
However, building the project like so now gives a linker error, because we are including Test.h
in both the main.cpp
and the Creation.cpp
compilation units. As a result, we have two methods that result in duplicate symbols. In order to remove the duplicate symbols, we need to declare both getTests
and runTests
to be inline, like this:
inline std::vector<TestInterface *> & getTests ()
{
static std::vector<TestInterface *> tests;
return tests;
}
inline void runTests ()
{
for (auto * test: getTests())
{
test->run();
}
}
Now, everything builds and runs again and we get the same result as before. The output displays the name of the single test we have so far:
testCanBeCreated Program ended with exit code: 0
The output remains unchanged from before. We haven’t added any more tests or changed what the current test does. We have changed how the tests are registered and run, and we have reorganized the project structure.