Hi, we’re having tens of unittest assemblies, each producing a trx file. Since the generated trx file name does not indicate what the unittest assembly name is, we used an extra option for the logger:
/Logger:trx;LogFilePrefix=$assemblyname
Each trx file is preceded by the assembly name,which makes the unittest much easier to find. However coverage files are not found by the sonar scanner, leading to 0.0% coverage.
Reason: the scanner assumes the file name of the trx is the same as the folder name in which the coverage file is located. This is not true when LogFilePrefix is used. It is also not true sometimes when you run your unit tests parallel. When trx files are generated in the same second, vstest.console.exe generates a trx file using the same time, followed by [1].trx or even [2].trx. In this case the coverage file is not found as well (leading to a few percent lower coverage).
The assumption that the folder name for the coverage file is directly related to the trx file name is therefore a poor one.
The actual name of the folder containing the coverage file is kept in the trx (attribute runDeploymentRoot), but is not used in the sonar scanner. It would make the discovery of coverage files better and more robust if the folder name in the trx file would be used.
I’ve seen that the most recent version of the scanner 10.1.1 still uses the assumption of the trx file name for the folder name.
Hi,
Welcome to the community!
Would you mind providing your SonarQube version number, as well as your analysis environment (e.g. Azure DevOps, GitHub Actions &etc)?
Additionally, an analysis log would help us better understand your situation.
Share the Scanner for .NET verbose logs
- Add
/d:"sonar.verbose=true"
to the…SonarScanner.MSBuild.exe
ordotnet sonarscanner
begin command to get more detailed logs- For example:
SonarScanner.MSBuild.exe begin /k:"MyProject" /d:"sonar.verbose=true"
- For example:
- “SonarQubePrepare” or “SonarCloudPrepare” task’s
extraProperties
argument if you are using Azure DevOps- For example:
- task: SonarCloudPrepare@3 inputs: SonarCloud: 'sonarcloud' organization: 'foo' scannerMode: 'dotnet' projectKey: 'foo_sonar-scanning-someconsoleapp' projectName: 'sonar-scanning-someconsoleapp' extraProperties: | sonar.verbose=true
- For example:
- The important logs are in the
END
step (i.e. SonarQubeAnalyze / SonarCloudAnalyze / “Run Code Analysis”)
Share the msbuild detailed logs
MsBuild.exe /t:Rebuild /v:d
or
dotnet build -v:d
Thx,
Ann
My SonarQube Server version is 9.9 (but will occur in 2025.1 as well). The analysis environment is Azure DevOps.
If i use “vstest.console.exe /Logger:trx” the trx files will have the name format <AccountName>_<ComputerName>_<sometimestamp>.trx
If i use “vstest.console.exe /Logger:trx;LogFilePrefix=TestAssembly1” the trx files will have the name format <TestAssembly1>_<targetframework>_<sometimestamp1>.trx
The relevant part of the logs:
Calling the TFS Processor executable...
Executing file <scannerpath>\SonarScanner.MSBuild.TFSProcessor.exe
......
Code coverage command line tool: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe
Fetching code coverage report information from TFS...
Attempting to locate a test results (.trx) file...
Looking for TRX files in: C:\Bld\<project>\<buildname>\TestResults
The following test results files were found: C:\Bld\<project>\buildname>\TestResults\<TestAssembly1>_net48_<sometimestamp1>.trx, C:\Bld\<project>\buildname>\TestResults\<TestAssembly2>_net48_<sometimestamp2>.trx, etc...
WARNING: None of the following coverage attachments could be found: <ComputerName>\<AccountName>_<ComputerName>_<sometimestamp3>.coverage, C:\Bld\<project>\buildname>\TestResults\<TestAssembly1>_net48_<sometimestamp1>\In\<ComputerName>\<AccountName>_<ComputerName>_<sometimestamp3>.coverage, C:\Bld\<project>\buildname>\TestResults\<TestAssembly1>_net48_<sometimestamp1>\In\<ComputerName>\<AccountName>_<ComputerName>_<sometimestamp3>.coverage. Trx file: C:\Bld\<project>\buildname>\TestResults\<TestAssembly1>_net48_<sometimestamp1>.trx
WARNING: None of the following coverage attachments could be found: <ComputerName>\<AccountName>_<ComputerName>_<sometimestamp4>.coverage, C:\Bld\<project>\buildname>\TestResults\<TestAssembly2>_net48_<sometimestamp2>\In\<ComputerName>\<AccountName>_<ComputerName>_<sometimestamp4>.coverage, C:\Bld\<project>\buildname>\TestResults\<TestAssembly2>_net48_<sometimestamp2>\In\<ComputerName>\<AccountName>_<ComputerName>_<sometimestamp4>.coverage. Trx file: C:\Bld\<project>\buildname>\TestResults\<TestAssembly2>_net48_<sometimestamp2>.trx
etc...
No code coverage attachments were found from the trx files.
Not using the fallback mechanism to detect binary coverage files.
Coverage report conversion completed successfully.
Process returned exit code 0
The TFS Processor has finished
The coverage file is searched by the sonar scanner in TestResults\<TestAssembly1>_net48_<sometimestamp>
(which is the name of the trx), but is stored in a folder with the name <AccountName>_<ComputerName>_<sometimestamp>
. This folder usage is default behaviour for all vstest.console.exe versions (VS2017-VS2022).
Each trx file remembers the folder in which the coverage file is kept:
<?xml version="1.0" encoding="utf-8"?>
<TestRun id= etc.>
<Times creation="<time>" queuing="<time>" etc. />
<TestSettings name="default" id="<guid>">
<Deployment runDeploymentRoot="<AccountName>_<ComputerName>_<sometimestamp>" />
</TestSettings>
The sonar scanner should use the runDeploymentRoot folder (if available!) to search for the coverage file. If you add this extra search path (if available) to the current list of search paths, the coverage files are always found (even without LogFilePrefix, e.g. running unit tests parallel).
e.g.
node = SelectSingleNode("/x:TestRun/x:TestSettings[@name='default']/x:Deployment",
nsmgr)
node.Attributes["runDeploymentRoot"]
Hi,
Have you tested this?
Thx,
Ann
It is a limitation of sonar-scanner, the version of SonarQube server is irrelevant. If the scanner does not find the coverage files, it cannot convert and upload them. Even the newest code of the scanner does not take the RunDeploymentRoot into account. In our environment we use scanner 9.2.1. Even in the master (sonar-scanner-msbuild/src/SonarScanner.MSBuild.TFS/TrxFileReader.cs at master · SonarSource/sonar-scanner-msbuild · GitHub) the code has not changed. Routine TryFindCoverageFileFromUri.
(B.t.w. I’ve made a copy of the 9.2.1 code and added the runDeploymentRoot to the search path. All coverage files are found).
Hello @Pieter_Klijnstra,
it looks like your analysis is correct. I created this Jira ticket.
If you like, you can contribute your changes to the scanner directly. Let me know if you are considering this and I will assist you with the PR.
Are you sure that we can contribute? This part of the contribution documentation seems suspect to me:
Before submitting the PR, make sure all tests are passing (all checks must be green).
Non Sonar contributors can’t run the checks, how could we make sure that all the checks are green?
You can run (most of) the tests locally and ask us to run the CI after we had a look at the PR.
The documentation probably should be updated. The mention “checks are green” may look confusing.