About My Code
I'm developing a video game in C++ using SDL3 — a cross-platform library that provides access to accelerated video, audio, controllers, and more. As part of development, I'm writing unit tests using a simple custom system that works like this:
Tests are created by inheriting from a base
Testclass and implementing itsrunmethod.A custom
Assertclass handles assertions.A class called
Vgx3TestRunnerruns all tests explicitly.
There's no automatic test discovery — if you write a new test, you need to register it manually: add a call to it in run(), and if it's a new test class, include it in Vgx3TestRunner.
For context, this guide is written for Visual Studio 2026 on Windows 11. The code itself should compile on Mac or Linux, but the coverage measurement steps are specific to Visual Studio 2026.
Measuring Coverage
Two things need to be done:
Enable the
/PROFILElinker flag.Run your tests and generate a coverage report.
Step 1 — Enable the /PROFILE Linker Flag
The /PROFILE flag makes your executable profilable by mapping C++ code to the underlying assembly. This is what enables coverage measurement.
Right-click your unit test project in Solution Explorer and select Properties.
Set the Configuration dropdown to Debug.
Go to C/C++ > Optimization and set Optimization to Disabled (/Od).
Go to Linker > Advanced and set Profile to Yes (/PROFILE).
Click Apply and OK, then do a full Rebuild.
Possible Build Error: Cannot Open SuchAndSuch.lib
After enabling /PROFILE, you may see a build error saying Visual Studio is unable to open a .lib file (e.g. SDL3.lib). This happens because /PROFILE disables Incremental Linking, which means Visual Studio no longer infers build order automatically. Your test project now needs its dependencies — like SDL3 — to be built first, but Visual Studio doesn't know that yet.
Tell Visual Studio about the dependency:
Right-click your test project in Solution Explorer and select Add > Reference... (or Build Dependencies > Project Dependencies, depending on your layout).
In the Projects tab, check the boxes next to SDL3, SDL3_image, and any other relevant dependencies.
Click OK.
Tell the linker where to find the output .lib files:
Right-click your test project and go to Properties.
Under Configuration Properties > General, note the Output Directory path — typically something like
$(SolutionDir)$(Platform)\$(Configuration)\.Go to Linker > General > Additional Library Directories and paste that same path macro there.
Click Apply and OK.
Now do a Clean Rebuild — your project should compile and run correctly.
Step 2 — Run Tests and Generate a Coverage Report
With /PROFILE enabled, you can use the Visual Studio 2026 built-in tool Microsoft.CodeCoverage.Console.exe to run your binary and measure coverage.
Open a terminal in Visual Studio via View > Terminal.
From your solution directory, run:
Microsoft.CodeCoverage.Console.exe collect .\x64\Debug\test.exe
Replace test.exe with your test project's binary name if it differs.
Your tests will run as normal, and a file called output.coverage will be generated. To view it, drag and drop it into Visual Studio from the Explorer window.
The report shows what percentage of your code was executed during the test run — 100% means full coverage, 0% means none. You'll notice it also measures coverage for your test infrastructure itself, which is usually just noise. To filter that out, you can add a .runsettings configuration file:
<!-- .runsettings -->
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector
friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Configuration>
<CodeCoverage>
<Sources>
<Exclude>
<!-- Don't measure coverage for the tests themselves -->
<SourcePath>.*src\.tests.*</SourcePath>
</Exclude>
</Sources>
<Functions>
<Exclude>
<!-- Don't measure coverage of the Assert class -->
<Function>.*Assert::.*</Function>
</Exclude>
</Functions>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
With this in place, the report will focus on the code that actually matters.
Aim for around 80% coverage — that's generally a healthy target. You don't need to chase 100%. Good luck!















