Shipyard is a simple and extensbile header only testing library intended to be used by extremely small C++ projects. It is meant to be a bare bones testing framework requiring almost no setup and thus comes at a cost of not being as featureful as other testing suites such as GoogleTest or CxxTest.
As a beginner C++ programmer, I find using most C++ third party libraries extremely difficult to use, especially when it comes to unit testing frameworks. Other languages such as Python, Go, even Java, have better unit testing support than C++ and I consider C++ to be quite a high level programming language and thus sought out to create a simple testing framework for a big integer library I was writing. It evolved into a project of its own and that project now lives on as shipyard.
It's a single header only framework that is written in concise and readable C++17 that anyone can hack on easily.
It's customisable in the sense that one can write his/her own Assert
function to use for different data types.
A number of Assert
s already exist for std::vector
, std::map
, std::unordered_map
, std::set
, and many more
besides assertions for primitive types like int
s and float
s.
There's a great tutorial over at Medium walking through most of shipyard's features. Read it here.
Download the header file for shipyard and place it inside a tests
directory of your project.
Include the functions or classes that you wish to test and start writing test functions. For example, say you have the following set of functions in an imaginary prime number library.
bool is_prime(uint64_t)
- to check whether a number is prime.uint64_t n_prime(uint64_t)
- to generate the nth prime number.std::vector<uint64_t> primes_till(uint64_t)
- to generate a vector of primes up until n.
You can structure your testing directory in a more modular fashion such that each file named test_<function_or_class_name>
has functions for testing said function or class but since this prime library is small enough, we'll be okay with just one file.
#include "shipyard.hpp"
#include "primelib.cpp"
void test_is_prime()
{
sy::AssertTrue(is_prime(5), "is_prime(5) == true");
sy::AssertFalse(is_prime(12), "is_prime(12) == false");
}
void test_n_prime()
{
sy::Assert(n_prime(10), 29);
sy::Assert(n_prime(100), 541);
}
void test_primes_till()
{
const auto primes = primes_till(10);
sy::Assert(primes, {2, 3, 5, 7, 11, 13, 17, 19, 23, 29});
}
Then you can run ship.py
and let it discover all the tests in the directory and generate the runner for you -
$ ship.py -v
$ cat test.cpp
/*
Generated by ship.py on Fri May 22 15:36:43 2020.
*/
#include "shipyard.hpp"
#include "test_primelib.cpp"
int main(int argc, char* argv[])
{
const auto tests = sy::create_tests({
TESTCASE(test_is_prime),
TESTCASE(test_n_prime),
TESTCASE(test_primes_till),
});
sy::run(tests, true);
return 0;
}
$ ls
primelib.cpp shipyard.hpp test.cpp test_primelib.cpp
$ clang++ test.cpp -o test -Wall
$ ./test
Running test_is_prime... done.
Running test_n_prime... done.
Running test_primes_till... done.
shipyard ships, no pun intended, with a few inbuilt Assert
functions for checking equality for various containers a custom
Assert
function can be easily written for any custom data type. All it needs to do it throw a AssertionError
defined in
the header on equality failure. For example, say you have some custom class called Person
and you want to assert that two
objects belong to the same "family" attribute of a class. Easily done -
void AssertSameFamily(const Person& p1, const Person& p2)
{
if (p1.family != p2.family)
throw AssertionError(p1.name " and " + p2.name " are not related");
}
The AssertionError
exception also has an optional std::string field for extra messages that can be used for some more
info on the assertion.
If you wish to run only a small subset of files then you can use the script provided with shipyard ship.py
. You can provide
a pattern for ship using -
$ ship.py -p test_n_prime
ship.py
also detects the dependencies from functions and thus only includes the dependent files that have the function in them.
Documentation coming soon.