Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Test-Driven Development with C++

You're reading from   Test-Driven Development with C++ A simple guide to writing bug-free Agile code

Arrow left icon
Product type Paperback
Published in Nov 2022
Publisher Packt
ISBN-13 9781803242002
Length 430 pages
Edition 1st Edition
Languages
Concepts
Arrow right icon
Author (1):
Arrow left icon
Abdul Wahid Tanner Abdul Wahid Tanner
Author Profile Icon Abdul Wahid Tanner
Abdul Wahid Tanner
Arrow right icon
View More author details
Toc

Table of Contents (21) Chapters Close

Preface 1. Part 1: Testing MVP
2. Chapter 1: Desired Test Declaration FREE CHAPTER 3. Chapter 2: Test Results 4. Chapter 3: The TDD Process 5. Chapter 4: Adding Tests to a Project 6. Chapter 5: Adding More Confirm Types 7. Chapter 6: Explore Improvements Early 8. Chapter 7: Test Setup and Teardown 9. Chapter 8: What Makes a Good Test? 10. Part 2: Using TDD to Create a Logging Library
11. Chapter 9: Using Tests 12. Chapter 10: The TDD Process in Depth 13. Chapter 11: Managing Dependencies 14. Part 3: Extending the TDD Library to Support the Growing Needs of the Logging Library
15. Chapter 12: Creating Better Test Confirmations 16. Chapter 13: How to Test Floating-Point and Custom Values 17. Chapter 14: How to Test Services 18. Chapter 15: How to Test With Multiple Threads 19. Index 20. Other Books You May Enjoy

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.

You have been reading a chapter from
Test-Driven Development with C++
Published in: Nov 2022
Publisher: Packt
ISBN-13: 9781803242002
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime