touca/touca.hpp
is the only header file of Touca SDK for C++ that you need to include in your regression test code. It provides all the functions necessary to configure the core library, capture results and submit them to the Touca server.
This section documents the API exposed by this header file.
Test Runner
Touca SDK has a high-level API that makes it easy to write tests and to run them using our built-in test runner.
The test runner abstracts away many of the common features expected of a test tool, such as parsing and processing configuration options, logging, error handling, managing test results on the filesystem and submitting them to the Touca server. An example implementation invokes touca::run()
after registering one or more test workflows via touca::workflow()
.
int main(int argc, char* argv[]) {
touca::workflow("is_prime", [](const std::string& testcase) {
const auto number = std::stoul(testcase);
touca::check("output", is_prime(number));
});
return touca::run(argc, argv);
}
-
int touca::run(int argc, char *argv[])
Serves as the main entrypoint to the built-in test runner.
Runs your test workflows one by one, with the appropriate configuration options, and to handle all captured test results by submitting them to the Touca server or writing them into the local filesystem.
This function works similar to the application’s
main()
function and is expected to be called within themain()
function. This design gives you the possibility to perform custom actions before and after invoking the test runner.See also
touca::workflow()
that should be called at least once prior to calling this function.- Parameters:
argc – number of arguments provided to the application
argv – list of arguments provided to the application
- Returns:
exit status that could be returned by the test application’s
main()
function
Adding Test Workflows
-
void touca::workflow(const std::string &name, const std::function<void(const std::string&)> workflow_callback, const std::function<void(WorkflowOptions&)> options_callback = nullptr)
Registers a test workflow to be run with one or more test cases by the Touca test runner.
While we make no assumption about the input to your code under test, the input parameter to function
workflow_callback
is always the identifier for your test case with typeconst std::string&
. It is up to the test workflow to perform the mapping from the identifier to the actual test input.See also
touca::WorkflowOptions
for a list of supported options.- Parameters:
name – name of this test workflow to be used as the test suite slug
workflow_callback – function that calls your code under test once for each test case.
options_callback – optional function that helps you set certain configuration options for this particular workflow.
-
struct WorkflowOptions
Configuration options that can be set for individual test workflows when calling the high-level API function
touca::workflow()
.Setting these parameters is optional. The test runner has built-in mechanism to attempt to find the appropriate value for each option based on the overall configuration options of the overall test.
Subclassed by touca::Workflow
Public Members
-
std::string suite
Name of the suite to be used that overrides the name of the workflow specified as the first parameter to
touca::workflow()
.
-
std::string version
Version of the code under test. When this parameter is not set, and is not otherwise specified when running the test, the test runner queries the Touca server to find the most recent submitted version for this suite and uses a minor increment of that version.
-
std::vector<std::string> testcases
List of test cases to be given one by one to the test workflow. When this parameter is not set, and is not otherwise specified when running the test, the test runner fetches and reuses the list of submitted test cases for the baseline version of this suite.
-
std::string suite
Configuring the Test Runner
-
void touca::configure_runner(const std::function<void(RunnerOptions&)> runner_options_callback)
High-level function that lets you customize the behavior of the built-in test runner at runtime, before running the test workflows.
Calling this function is optional. In most cases, it is easier to configure the test runner via command-line arguments, environment variables, or by using a configuration profile.
Any customization using this function will be applied before performing other methods of configuration (such as parsing command-line arguments).
int main(int argc, char* argv[]) { touca::configure_workflow([](touca::RunnerOptions& x) { x.save_binary = true; }); touca::workflow("is_prime", [](const std::string& testcase) { const auto number = std::stoul(testcase); touca::check("output", is_prime(number)); }); return touca::run(argc, argv); }
See also
touca::RunnerOptions
for a list of supported options.- Parameters:
runner_options_workflow – function that helps you customize the test runner behavior.
-
struct RunnerOptions : public touca::ClientOptions
Configuration options supported by the built-in test runner.
Public Members
-
bool save_binary = false
Store all the data points captured for each test case into a local file in binary format. Touca binary archives can later be inspected using the Touca CLI and submitted to a Touca server instance.
-
bool save_json = false
Store all the data points captured for each test case into a local file in JSON format. Unlike Touca binary archives, these JSON files are only helpful for manual inspection of the captured test results and are not supported by the Touca server.
-
bool overwrite_results = false
Overwrite the locally generated test results for a given testcase if the results directory already exists.
-
bool no_color = false
Do not use ANSI colors when reporting the test progress in the standard output.
-
bool redirect_output = true
Capture the standard output and standard error of the code under test and redirect them to a local file.
-
bool skip_logs = false
Indicates whether to generate a copy of the standard output of the test into a
Console.log
file.
-
std::string config_file
Relative or full path to a configuration file to be loaded and applied at runtime.
-
std::string output_directory
Relative or full path to the directory in which Touca test results are written, when the runner is configured to write them into the local filesystem.
-
std::string log_level = "info"
Level of detail to use when publishing log events to the external loggers.
-
std::vector<std::string> testcases
Set of testcases to feed one by one to all the registered workflows. When not provided, the test runner uses the set of testcases configured for each workflow. If that set is empty, the test runner attempts to retrieve and reuse the set of testcases submitted for the baseline version of each workflow.
-
std::string workflow_filter
Limits the test to running the specified workflow as opposed to all the registered workflows.
-
std::vector<Workflow> workflows
The set of all registered workflows.
-
bool submit_async = false
Submits test results asynchronously if set.
-
bool save_binary = false
-
void touca::add_sink(std::unique_ptr<Sink> sink, const Sink::Level level = Sink::Level::Info)
Registers a sink to subscribe to the test runner log events.
- Parameters:
sink – sink instance to be called when a log event is published
level – minimum level of detail to subscribe to
Core Library
Touca C++ SDK provides a separate lower-level Client API that offers more flexibility and control over how tests are executed and how their results are handled. This API is most useful when integrating Touca with other existing test frameworks.
Configuring the Library
-
void touca::configure(const std::function<void(ClientOptions&)> options = nullptr)
Attempts to configure the core Touca library.
Must be called before declaring testcases or adding results to the client.
touca::configure([](ClientOptions& x){ x.api_key = "03dda763-62ea-436f-8395-f45296e56e4b" x.api_url = "https://api.touca.io" x.team = "acme", x.students = "students", x.version = "v1.0", });
Client is considered configured if it can capture test results and store them locally on the filesystem. To do so, configuration options
team
,suite
, andversion
shall be provided, directly or indirectly, together in a single call, or separately in a sequence of calls, in order for the client to be considered as configured. These options may be specified, in part or in full, as components of the configuration parameterapi-url
.In addition to the configuration parameters above, the parameters
api-url
andapi-key
shall be provided for the client to be able to submit captured test results to the server. As an example, the same configuration options above could have been provided via the following code snippet.touca::configure([](ClientOptions& x){ x.api_key = "03dda763-62ea-436f-8395-f45296e56e4b" x.api_url = "https://api.touca.io/@/acme/student/v1.0" });
If the API URL is missing and API Key is set, the API URL will be set to https://api.touca.io.
Since the function is designed to never throw and to allow users to configure the client through a sequence of separate calls, we recommend that you use
touca::is_configured()
to check if the client is configured and learn about any potential error usingtouca::configuration_error()
.if (!touca::is_configured()) { std::cerr << touca::configuration_error() << std::endl; }
See also
touca::ClientOptions
for a list of supported configuration parameters- Parameters:
options – a callback function for setting configuration parameters
-
struct ClientOptions
Configuration options supported by the low-level Core API library.
Use the
touca::configure
function for setting these options programmatically. When using the test runner, you can set any subset of these options without hard-coding the values using a variety of methods such as command-line arguments, environment variables, JSON-formatted configuration file, Touca CLI configuration profiles, etc. Seetouca::RunnerOptions
to learn more.Subclassed by touca::RunnerOptions
Public Members
-
std::string api_key
API Key issued by the Touca server that identifies who is submitting the test results.
Since the value should be treated as a secret, we strongly recommend that you do not hard-code this option and pass it via other methods such as setting the environment variable
TOUCA_API_KEY
(ideal for the CI environment) or using the Touca CLI to set this option in your configuration profile to be automatically loaded at runtime (ideal for local development).
-
std::string api_url
URL to Touca server API
Defaults to
when
api_key
is specified. If you are self-hosting the Touca server, we encourage using the Touca CLI to set this option in your configuration profile to be automatically loaded at runtime.
-
std::string team
Slug of your team on the Touca server
Since it is unlikely for your team slug to change, we encourage using the Touca CLI to set this option in your configuration profile to be automatically loaded at runtime.
-
std::string suite
Name of the test suite to submit test results to
When using the test runner, value of the first parameter to
touca::workflow
is used by default.
-
std::string version
Version of your code under test
Since this version is expected to change, we encourage setting option via the environment variable
TOUCA_TEST_VERSION
or passing it as a command-line option.When using the test runner, you may also skip setting this option to let the test runner query the Touca server for the most recent version of your suite and use a minor version increment.
-
bool offline = false
Disables all communications with the Touca server
Determines whether client should connect with the Touca server during the configuration. Will be set to
false
when neitherapi_url
norapi_key
are set.
-
bool concurrency = true
Isolates the testcase scope to calling thread
Determines whether the scope of test case declaration is bound to the thread performing the declaration, or covers all other threads. Defaults to
true
.If set to
true
, when a thread callstouca::declare_testcase
, all other threads also have their most recent test case changed to the newly declared test case and any subsequent call to data capturing functions such astouca::check
will affect the newly declared test case.
-
std::string api_key
-
bool touca::is_configured()
Checks if the client is configured to perform basic operations including capturing data points and storing them locally on the filesystem. Note that when
api_key
andapi_url
are missing, the client is considered as configured even though it cannot submit the test results to the server.See also
touca::configuration_error()
for extracting the most recent reason whentouca::configure()
is called but the client is not configured.- Returns:
true if the client is configured to perform basic operations.
-
std::string touca::configuration_error()
Provides the most recent error, if any, encountered during client configuration.
See also
touca::is_configured()
for checking if the client is configured before attempting to access and handle any configuration error.- Returns:
short description of the most recent configuration error
Registers a custom logger that is notified when an event of potential interest takes place.
This function enables users to register their own logger derived from
touca::logger
and listen for log events generated by the client library. Log events include warnings and errors if client library is misused or fails to perform an instructed action. Adding a logger is optional.- Parameters:
logger – a custom logger that is notified of log events generated by the core library.
Declaring Testcases
-
void touca::declare_testcase(const std::string &name)
Declares the name of the testcase to which all subsequent results will be submitted until a new testcase is declared.
Unless configuration options
concurrency
is set to false, when a thread callsdeclare_testcase
all other threads also have their most recent testcase changed to the newly declared one.- Parameters:
name – name of the testcase to be declared
-
void touca::forget_testcase(const std::string &name)
Removes all logged information associated with a given testcase.
Removes from memory, all information that is logged for the previously declared testcase, for all the threads, regardless of whether configuration option
concurrency
is set.This function does not remove the test results results from the server, in case they are already submitted. It clears all information about that testcase from the client library such that switching back to an already declared or already submitted testcase would behave similar to when that testcase was first declared.
Calling this function is useful in long-running regression tests, after submission of the testcase to the server, if memory consumed by the client library is a concern or if there is a risk that a future testcase with a similar name may be executed.
- Parameters:
name – name of the testcase to be removed from memory
Capturing Test Results
-
template<typename Char, typename Value>
void touca::check(Char &&key, const Value &value) Captures the value of a given variable as a test result for the declared testcase and associates it with the specified key.
Primary data capturing function for adding test results for the declared testcase.
- Template Parameters:
Char – type of string to be associated with the value stored as a result. Expected to be convertible to
std::basic_string<char>
.Value – original type of value
value
to be stored as a result in association with the given keykey
.
- Parameters:
key – name to be associated with the logged test result.
value – value to be logged as a test result.
-
template<typename Char, typename Value>
void touca::assume(Char &&key, const Value &value) Logs a given value as an assumption for the declared testcase and associates it with the specified key.
Assumptions are a special category of data points that are hardly ever expected to change for a given test case between different versions of the workflow.
Assumptions are treated differently by the Touca server: The server specially highlights assumptions if they are different between two test versions and removes them from user focus if they remain unchanged. Therefore, assumptions are particularly helpful for verifying assumptions about input data and their properties.
See also
touca::check()
as the primary data capturing function.- Template Parameters:
Char – type of string to be associated with the value stored as an assumption. Expected to be convertible to
std::basic_string<char>
.Value – original type of value
value
to be stored as an assumption in association with given keykey
.
- Parameters:
key – name to be associated with the logged test result.
value – value to be logged as an assumption
-
template<typename Char, typename Value>
void touca::add_array_element(Char &&key, const Value &value) Adds a given data point as an element of an ordered set of data points that are stored as one single test result entity for the testcase which is associated with the specified key.
Could be considered as a helper utility function. This method is particularly helpful to log a list of elements as they are found:
for (const auto number : numbers) { if (isPrime(number)) { touca::add_array_element("prime numbers", number); touca::add_hit_count("number of primes"); } }
This pattern can be considered as a syntactic sugar for the following alternative:
std::vector<unsigned> primes; for (const auto number : numbers) { if (isPrime(number)) { primes.emplace_back(number); } } if (!primes.empty()) { touca::check("prime numbers", primes); touca::check("number of primes", primes.size()); }
The items added to the list are not required to be of the same type. The following code is acceptable:
touca::add_array_element("elements", 42); touca::add_array_element("elements", "forty three");
See also
touca::check()
as the primary data capturing function.- Since
v1.1
- Template Parameters:
Char – type of string to be associated with the value stored as an element. Expected to be convertible to
std::basic_string<char>
.Value – original type of value
value
to be stored as an element of an array associated with given keykey
.
- Parameters:
key – name to be associated with the logged test result.
value – element to be appended to the array
- Throws:
touca::detail::runtime_error – if the specified key is already associated with a test result whose type is not a derivative of
touca::array
.
-
void touca::add_hit_count(const std::string &key)
Increments the value of the data point associated with key
key
. Creates the data point with the initial value of1
if it does not exist.May be considered as a helper utility function. This method is particularly helpful to track variables whose values are determined in loops with indeterminate execution cycles:
for (const auto number : numbers) { if (isPrime(number)) { add_array_element("prime numbers", number); add_hit_count("number of primes"); } }
This pattern can be considered as a syntactic sugar for the following alternative:
std::vector<unsigned> primes; for (const auto number : numbers) { if (isPrime(number)) { primes.emplace_back(number); } } if (!primes.empty()) { touca::check("prime numbers", primes); touca::check("number of primes", primes.size()); }
See also
touca::check()
as the primary data capturing function.- Since
v1.1
- Parameters:
key – name to be associated with the logged test result.
- Throws:
touca::detail::runtime_error – if the specified key is already associated with a test result which was not an integer.
Capturing Metrics
-
void touca::add_metric(const std::string &key, const unsigned duration)
Adds a performance measurement collected with the help of this library as a performance benchmark (metric).
- Since
v1.2.0
- Parameters:
key – name to be associated with the performance metric
duration – duration in number of milliseconds
-
void touca::start_timer(const std::string &key)
Starts performance measurement for a given metric.
Records the time of invocation of this function, associates it with the given key and awaits a future call to
stop_timer
with the same key to log the duration as a performance metric.- Since
v1.1
- Parameters:
key – name to be associated with the performance metric
-
void touca::stop_timer(const std::string &key)
Stops performance measurement for a given metric.
Logs a performance metric whose value is the duration between this call and a previous call to
start_timer
with the same key.- Since
v1.1
- Parameters:
key – name to be associated with the performance metric
-
class scoped_timer
a simple class that helps clients log the duration between its instantiation and destruction as a performance metric.
-
TOUCA_SCOPED_TIMER
convenience macro for logging performance of a function as a performance metric.
Saving Test Results
-
void touca::save_binary(const std::string &path, const std::vector<std::string> &testcases = {}, const bool overwrite = true)
Stores the test results in binary format in a file with the specified path.
Stores the test results assigned to given set of testcases in a file with the specified path in binary format. We do not recommend as a general practice for regression test tools to locally store their test results. This feature may be helpful for special cases such as when test tools have to be run in environments that have no access to the Touca server (e.g. running with no network access).
- Parameters:
path – path to file in which test results should be stored
testcases – set of names of testcases whose results should be stored. if given set is empty, all test cases will be stored in the specified file.
overwrite – determines whether to overwrite any file that exists in the specified
path
. Defaults to true.
-
void touca::save_json(const std::string &path, const std::vector<std::string> &testcases = {}, const bool overwrite = true)
Stores test results in JSON format in a file with the specified path.
Stores test results assigned to given set of testcases in a file with the specified path in JSON format.
- Parameters:
path – path to file in which test results should be stored
testcases – set of names of testcases whose results should be stored to disk. if given set is empty, all testcases will be stored in the specified file.
overwrite – determines whether to overwrite any file that exists in the specified
path
. Defaults to true.
Submitting Test Results
-
Post::Status touca::post(const Post::Options &options = {})
Submits all test results recorded so far to Touca server.
Posts all test results of all testcases declared by this client to Touca server in flatbuffers format. Should only be called after the client is configured.
It is possible to call touca::post() multiple times during runtime of the test tool. Test cases already submitted to the server whose test results have not changed, will not be resubmitted. It is also possible to add test results to a testcase after it is submitted to the server. Any subsequent call to touca::post() will resubmit the modified testcase.
- Throws:
touca::detail::runtime_error – if client is not configured or that it is configured to operate without communicating with the server.
- Returns:
enum indicating the status of submitted test results.
Sealing a Version
-
void touca::seal()
Notifies Touca server that all test cases were executed and no further test result is expected to be submitted.
Expected to be called by the test tool once all test cases are executed and all test results are posted.
Sealing the version is optional. The Touca server automatically performs this operation once a certain amount of time has passed since the last test case was submitted. This duration is configurable from the “Settings” tab in “Suite” Page.
- Since
v1.3
- Throws:
touca::detail::runtime_error – if client is not configured or that it is configured to operate without communicating with the server.
Extending Touca Type System
-
template<typename T, typename>
struct serializer Non-specialized template declaration of conversion logic for handling objects of custom types by the Touca SDK for C++.
Allows users developing regression tools to provide explicit full specialization of this class that makes it convenient to pass objects of their non-trivial type directly to Touca API functions that accept test results.
The following example illustrates a specialization of serializer for a custom type
Date
.struct Date { const unsigned short year; const unsigned short month; const unsigned short day; }; template <> struct touca::serializer<Date> { data_point serialize(const Date& value) { return object("Date") .add("year", value.year) .add("month", value.month) .add("day", value.day); } };
Once declared, this specialization allows user to directly pass objects of type
Date
to Touca server API that accepts test results.Date date { 1961, 8, 4 }; touca::check("birthday", date);
Noteworthy, that declaring a conversion logic for
Date
, enables objects of this type to be used as smaller pieces of even more complex types:struct Person { const std::string name; const Date birthday; }; template <> struct touca::serializer<Person> { data_point serialize(const Person& value) { return object("Person") .add("name", val.name) .add("birthday", val.birthday); } }; Person person { "alex", { 1961, 8, 4 } }; touca::check("person", person);
- Template Parameters:
T – type whose handling logic is to be implemented in
serialize
member function.