Skip to content
This repository has been archived by the owner on Jul 17, 2023. It is now read-only.

Boost Test Adapter Design

Brian Gatt edited this page Jul 22, 2016 · 9 revisions

Boost Unit Test Adapter Design

The Boost Unit Test Adapter allows users to discover and execute Boost Test test cases from within the Visual Studio IDE. The adapter abides to Visual Studio's Microsoft.VisualStudio.TestPlatform.ObjectModel specifications which, in brief, expect an implementation to list tests available within a compiled module and be able to execute tests individually given either a module or a test case specification as input. For more information regarding Visual Studio's test platform, refer to the Visual Studio Test Platform Primer article.

The following is a high-level description of how the Boost Unit Test Adapter handles test discovery and execution for native C++ modules containing Boost Tests.

Test Discovery

Once an exe or dll is successfully compiled and filtered by path, the Boost Unit Test Adapter needs to verify if the module contains Boost Tests. Identifying test cases from C++ native modules has its fair share of challenges. In any case, test discovery should not be limited to one approach; multiple approaches should be available and one should fall-back to the other in case an approach fails to find tests.

An appropriate discovery strategy is first identified for a given set of modules and later, these strategies are applied.

Currently, there are 2 main approaches to discovery (hereby referred simply as discoverers) defined.

List Content Discoverer

Boost Test 3 test runner allows test cases to be listed. A module is first tested to see whether this functionality is available and if so, the module is registered with this discovery approach. Only modules which are deemed as safe, that is modules which contain the --list_content debug symbol, are taken into consideration but this behaviour can be overriden via the <ForceListContent> configuration value which is ideal for cases where BOOST Test is dynamically linked. DOT test listings are then parsed via an ANTLR4 generated grammar and later identified to the Visual Studio APIs.

External Discoverer

Via test adapter configuration, users can specify an external Boost Test runner which should be responsible of listing and executing tests. If an external discoverer is configured, this takes precedence over the 'internal' ones. External test runners also make use of the list content discovery mechanism.

Any and all discovered tests by any of the mentioned approach are then identified to the Visual Studio APIs. Test suite information, label information and enabled status are also provided to Visual Studio so that it is possible to categorize test cases via said traits.

Test Execution

Once tests are discovered from a module, the Boost Test Adapter attempts to execute test cases. Each test case is individually executed in a separate process so that test results can be communicated immediately back to Visual Studio unless specified otherwise via the <TestBatchStrategy> configuration value. Results generated by the process are later parsed and sent to Visual Studio. Note that from Visual Studio 2015 Update 1, tests may also be executed in parallel.

Test Execution Environment

Test modules are executed as a separate process. On completion, test results (located within the user's temporary folder) are then parsed and communicated to Visual Studio. This process normally runs within the directory where the module is located i.e. the working directory is the same directory in which the executable is located and uses the general environment variables. These two properties can be modified via Visual Studio's Debugging property page or, in the case of working directory, via the .runsettings configuration.

Code Coverage

Executing test cases individually can be slow, especially for code coverage since symbols need to be reloaded per process spawn. In an attempt to minimize this cost, tests are batched per test suite. Test cases contained within the same test suite are then executed in one go.