The Tesults web app is designed for desktop browsers. Sign up and configure your project on a laptop or desktop. Use the iOS app or Android app to view results on the go.

GoogleTest (gtest) test reporting

Using GoogleTest (gtest) for C++ testing? Follow the instructions below to report results. If you are not using GoogleTest see the C++ docs for integrating with the lower-level library directly.

Installation

gtest-tesults is a header-only Google Test event listener that depends on the Tesults C++ library. Both can be added via CMake FetchContent.

CMake FetchContent (recommended)

Add the following to your CMakeLists.txt:

include(FetchContent)

FetchContent_Declare(
  tesults
  GIT_REPOSITORY https://github.com/tesults/cpp.git
  GIT_TAG        main
  GIT_SHALLOW    TRUE
)
FetchContent_MakeAvailable(tesults)

FetchContent_Declare(
  gtest_tesults
  GIT_REPOSITORY https://github.com/tesults/gtest-tesults.git
  GIT_TAG        main
  GIT_SHALLOW    TRUE
)
FetchContent_MakeAvailable(gtest_tesults)

target_link_libraries(your_tests PRIVATE
  tesults
  gtest_tesults
  GTest::gtest
)

Manual copy

Alternatively, copy the single header file gtest_tesults.h directly from the GitHub repository into your project. Ensure that both the Tesults C++ library and GoogleTest headers are on your include path.

System dependencies

The Tesults C++ library requires libcurl and OpenSSL. macOS (Homebrew):

brew install curl openssl

Linux (apt):

apt install libcurl4-openssl-dev libssl-dev

Configuration

gtest-tesults automatically registers its listener at startup — no changes to your test code or main() are required. Just set the TESULTS_TARGET environment variable and run your tests as usual.

Environment variable (recommended)

Set TESULTS_TARGET to your Tesults target token before running your tests:

TESULTS_TARGET=token ./your_tests

Basic configuration complete

That's it. No code changes needed. gtest-tesults detects TESULTS_TARGET at startup and registers the listener automatically. If the variable is not set, nothing happens and your tests run as normal.

The test suite name is taken from the first argument to TEST or TEST_F and the test case name from the second.

TEST(CalculatorTest, Addition) {
  EXPECT_EQ(2 + 2, 4);
}

TEST(CalculatorTest, Subtraction) {
  EXPECT_EQ(10 - 3, 7);
}

CalculatorTest is reported as the suite and Addition / Subtraction as the test case names.

Config file (optional)

Instead of putting the token directly in TESULTS_TARGET you can use a key name and point to a config file. This keeps tokens out of scripts and CI environment definitions.

tesults.cfg
# Tesults target tokens
target1=eyJ0eXAiOiJ...
web-qa=eyJ0eXAiOiK...
ios-staging=eyJ0eXAiOiL...
TESULTS_TARGET=target1 TESULTS_CONFIG=tesults.cfg ./your_tests

Command-line args (alternative)

If you prefer to pass the token as a command-line argument rather than an environment variable, you can provide a custom main(). Call config_from_args before testing::InitGoogleTest so GoogleTest does not see the unknown --tesults-* flags:

#include <gtest/gtest.h>
#include <gtest_tesults/gtest_tesults.h>

int main(int argc, char* argv[]) {
  auto cfg = gtest_tesults::config_from_args(argc, argv);
  testing::InitGoogleTest(&argc, argv);
  if (!cfg.target.empty()) {
    testing::UnitTest::GetInstance()->listeners().Append(
      new gtest_tesults::TesultsListener(cfg)
    );
  }
  return RUN_ALL_TESTS();
}
./your_tests --tesults-target=token

A config file can also be used with the key method:

./your_tests --tesults-target=target1 --tesults-config=tesults.cfg

When using a custom main(), pass the token via --tesults-target rather than the TESULTS_TARGET env var to avoid registering the listener twice.

Enhanced reporting

Call these functions from inside any TEST or TEST_F body to attach additional data to the test case. No arguments or state object is needed — gtest-tesults identifies the current test automatically.

file

Attach a file to the current test case. Call multiple times to attach more than one file.

gtest_tesults::file("/path/to/log.txt");

description

Set a description for the current test case.

gtest_tesults::description("Verifies that addition returns the correct sum");

custom

Add a custom field and value to the current test case.

gtest_tesults::custom("environment", "staging");

step

Add a step to the current test case. Steps are reported in order.

gtest_tesults::step({"setup", "pass", "Initialise connection", ""})
gtest_tesults::step({"request", "pass", "Send HTTP request", ""})
gtest_tesults::step({"assert", "fail", "Check response code", "Expected 200 got 404"})

A Step has four fields in order: name, result ("pass", "fail", or "unknown"), desc, and reason.

Complete example

TEST(PaymentTest, SuccessfulCharge) {
  gtest_tesults::description("Verifies a valid card is charged successfully");
  gtest_tesults::custom("environment", "staging");
  gtest_tesults::step({"setup", "pass", "Create payment intent", ""})

  // run the test ...
  EXPECT_EQ(charge_result, "success");

  gtest_tesults::file("/tmp/charge-response.json");
}

Files generated by tests

--tesults-filesOptional

Provide the top-level directory where files generated during testing are saved. Files including logs, screenshots, and other artifacts will be automatically uploaded to Tesults.

TESULTS_TARGET=token TESULTS_FILES=/path/to/files ./your_tests

Or with command-line args if using a custom main():

./your_tests --tesults-target=token --tesults-files=/path/to/files

Files must be saved within a specific directory structure during the test run:

files-path/
  SuiteName/
    TestName/
      file.log
      screenshot.png

For build files the suite is always [build]:

files-path/
  [build]/
    BuildName/
      build.log

Caution: If uploading files the time taken to upload is entirely dependent on your network speed. Typical office upload speeds of 100 - 1000 Mbps should allow upload of even hundreds of files quite quickly, just a few seconds, but if you have slower access it may take hours. We recommend uploading a reasonable number of files for each test case. When starting out test without files first to ensure everything is setup correctly.

During a test run, save test generated files such as logs and screenshots to a local temporary directory. At the end of the test run all files will automatically be saved to Tesults as long as you save files in the directory structure below. Omit test suite folders if not using test suites.
  • expanded temporary folder
    • expanded Test Suite A
      • expanded Test 1
        • test.log
        • screenshot.png
      • expanded Test 2
        • test.log
        • screenshot.png
    • expanded Test Suite B
      • expanded Test 3
        • metrics.csv
        • error.log
      • expanded Test 4
        • test.log

Build

--tesults-build-nameOptional

Use this to report a build version or name for reporting purposes.

--tesults-build-name=1.0.0

--tesults-build-resultOptional

Use this to report the build result, must be one of [pass, fail, unknown].

--tesults-build-result=pass

--tesults-build-descriptionOptional

Use this to report a build description for reporting purposes.

--tesults-build-description=added new feature

--tesults-build-reasonOptional

Use this to report a build failure reason.

--tesults-build-reason=build error line 201 somefile.cpp

Result Interpretation

Result interpretation is not currently supported by this integration. If you are interested in support please contact help@tesults.com.

Go to the Configuration menu.

Configuration menu

Select Build Consolidation.

When executing multiple test runs in parallel or serially for the same build or release, results are submitted to Tesults separately and multiple test runs are generated on Tesults. This is because the default behavior on Tesults is to treat each results submission as a separate test run.

This behavior can be changed from the configuration menu.

Build Consolidation

Click 'Build Consolidation' from the Configuration menu to enable and disable consolidation for a project or by target.

When build consolidation is enabled multiple test runs submitted at different times, with the same build name, will be consolidated into a single test run by Tesults automatically.

This is useful for test frameworks that run batches of test cases in parallel. If you do not have a build name to use for consolidation, consider using a timestamp set at the time the test run starts.

Build Replacement

When build consolidation is enabled, an additional option, build replacement can optionally be enabled too. Just as with build consolidation, when multiple test runs are submitted with the same build name the results are consolidated, but with replacement enabled, if there are test cases with the same suite and name received multiple times, the last received test case replaces an existing test case with the same suite and name. This may be useful to enable in situations where test cases are re-run frequently and you do not want new test cases to be appended and instead want them to replace older test cases. This option is generally best left disabled, unless test cases are often re-run for the same build and you are only interested in the latest result for the run.

Dynamically created test cases

If you dynamically create test cases, such as test cases with variable values, we recommend that the test suite and test case names themselves be static. Provide the variable data information in the test case description or other custom fields but try to keep the test suite and test name static. If you change your test suite or test name on every test run you will not benefit from a range of features Tesults has to offer including test case failure assignment and historical results analysis. You need not make your tests any less dynamic, variable values can still be reported within test case details.

Proxy servers

Does your corporate/office network run behind a proxy server? Contact us and we will supply you with a custom API Library for this case. Without this results will fail to upload to Tesults.

Have questions or need help? Contact us

ROS 2

ROS 2 C++ packages use ament_add_gtest() which links gtest_main — no custom main() is available. The environment variable approach described above works out of the box. Add the FetchContent blocks to your package CMakeLists.txt and link the libraries:

ament_add_gtest(your_tests test/your_tests.cpp)
target_link_libraries(your_tests PRIVATE
  tesults
  gtest_tesults
)

Then set TESULTS_TARGET when running tests with colcon:

TESULTS_TARGET=token colcon test

Or in a launch file:

<env name="TESULTS_TARGET" value="token"/>
<env name="TESULTS_CONFIG" value="/path/to/tesults.cfg"/>