21

This article describes setting the VS Code settings to point the debugging target at the build output of the unit test project. I have therefore set mine like this:

{
    "explorer.confirmDragAndDrop": false,
    "git.allowForcePush": true,
    "git.autofetch": true,
    "window.zoomLevel": 0,
    "csharp.unitTestDebuggingOptions": {
        "sourceFileMap": {
           "C:\\git\\MsTester\\bin\\Debug\\netcoreapp2.1": "C:\\git\\MsTester\\bin\\Debug\\netcoreapp2.1"
        }
    },
    "files.autoSave": "afterDelay",
    "files.exclude": {
        "**/bin": true,
        "**/node_modules": true,
        "**/obj": true
    },
    "csharpfixformat.style.spaces.insideEmptyBraces": false,
    "csharpfixformat.style.braces.allowInlines": false,
    "csharpfixformat.style.spaces.beforeParenthesis": false,
    "csharpfixformat.style.spaces.afterParenthesis": false,
    "csharp.format.enable": false,
    "extensions.ignoreRecommendations": true
}

However, I am not sure how to setup the launch.json to kick off the dotnet test so that it can attach the debugger.

This is what I've got currently:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "MsTester",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/MsTester/bin/Debug/netcoreapp2.1/MsTester.dll",
            "windows": {
                "args": [
                    "--filter",
                    "TestCategory=lbshell",
                    "--logger",
                    "trx",
                    "--results-directory",
                    ".\\TestResults",
                    "--settings",
                    ".\\Features\\runsettings.xml"
                ],
            },
            "cwd": "${workspaceFolder}/MsTester",
            "console": "internalConsole",
            "stopAtEntry": false,
            "internalConsoleOptions": "openOnSessionStart"
        },
    ]
}

Is there an option to tell VS Code that it needs to execute dotnet test instead of dotnet run?

I was hoping this page would indicate how to do that, but it does not.

wejoey
  • 216
  • 1
  • 3
  • 14
Matt W
  • 11,753
  • 25
  • 118
  • 215

3 Answers3

28

All credit is due to @Lance U. Matthews as he posted this as a comment to an answer to the question: How does one debug an MSTest in VSCode? . I am reposting this as a proper answer because he hasn't done so in a year.

The following answer has been tested on VSCode v1.62.3 and dotnet tools v5.0.403.

Assuming you have a .NET solution with a structure like this:

mysolution.sln
tests\
  |---> tests.csproj
  |---> UnitTest1.cs
.vscode\
  |---> launch.json
  |---> tasks.json

Copy the following into the tasks.json file:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        { 
            "label": ".NET Core Test with debugger", 
            "type": "process", 
            "isBackground": true, 
            "command": "dotnet", 
            "args": [ "test" ], 
            "options": 
                { 
                    "cwd": "${workspaceFolder}/tests", 
                    "env": 
                    { 
                        "VSTEST_HOST_DEBUG": "1" 
                    }, 
                }, 
            "group": "test", "presentation": 
                { 
                    "echo": true,
                    "reveal": "always",
                    "focus": false,
                    "panel": "shared"
                },
            "problemMatcher": [] 
        },
    ]
}

And this into the launch.json file:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach"
        }
    ]
}

Now set a breakpoint anywhere in your UnitTest1.cs file and run .NET Core Test with debugger task (Terminal->Run task...). The Test Execution Command Line Tool should launch and at the bottom of your terminal should be something like: enter image description here Your Process Id will certainly be different but that is expected behavior.

Now you need to switch to "Run and Debug" tab (ctrl+shift+d) and select ".NET Core Attach" (it should be in the upper left part of the VSCode). Provide the process id that appeared previously in the terminal: enter image description here Now click F5 once and you should reach one of your breakpoints.

Ricardo Valente
  • 581
  • 1
  • 10
  • 14
zajer
  • 649
  • 6
  • 17
  • Great Answer! it should be documented :) – Mojtaba Pourmirzaei Apr 02 '22 at 09:41
  • 2
    The process name would be `testhost.exe`, and not the first highlighted process in the screenshot. Might not be obvious for some like myself x). Also I had to press the "Resume Execution" debug button to continue getting the debug symbols to load. – gitsitgo Nov 01 '22 at 07:07
  • With `prelaunchTask` and `"processName":"testhost.exe"` in launch.json, you do not need to run task manually. – mingpepe Jul 19 '23 at 12:13
11

This may not answer solve your problem of passing the arguments entirely, but may solve the problem of passing runsettings parameters to the code being debugged. Using this method, I was able to pass the contents of runsettings to my code when running the debugger (i.e. when I click "Debug Test" above the method):

Test Method Example

What I ended up doing is this:

First, I wrote a bit of code that will read from the settings file (via TestContext) OR from the user environment if the key was not available in the settings file, i.e.:


[ClassInitialize]
public static void TestClassInitialize(TestContext context)
{
    v = Settings.GetSettingValueFromContextOrEnvironment("v", context);
}

Here is the implementation of GetSettingValueFromContextOrEnvironment:

/// <summary>
/// Attempts to read a setting value from the context (populated through runsettings). If the
/// key is not present in the context, the value will be read from the user environment variable
/// instead.
/// 
/// This allows running the unit test code in VSCode debugger that currently doesn't seem to allow
/// passing runsettings file to the DLL.
/// </summary>
/// <param name="name"></param>
/// <param name="context"></param>
/// <returns></returns>
public static String GetSettingValueFromContextOrEnvironment(string name, TestContext context){
    if (context.Properties.ContainsKey(name)){
        return context.Properties[name].ToString();
    } else {
        String envVar = Environment.GetEnvironmentVariable(name, System.EnvironmentVariableTarget.User);

        if (envVar == null){
            throw new Exception(String.Format("Environment variable '{0}' was not available neither in the context file nor in the environment.", name));
        } else {
            return envVar;
        }
    }
}

I then wrote a Powershell that will read my settings file to parse parameters and set them as user environment variables, like this:

<# This script updates user environment variables with parameters stored in *.runsettings file that is provided to it as the only argument on the command line.

Example usage:
    .\set_settings_env.ps1 local.runsettings
#>

param (
    [Parameter(Mandatory=$true)][string]$settings_file
)


[xml]$xml = Get-Content $settings_file
foreach( $parameter in $xml.RunSettings.TestRunParameters.Parameter) 
{
    write-host("Setting environment variable: " + $parameter.name)
    [Environment]::SetEnvironmentVariable($parameter.name, $parameter.value, "User")
}

So now I am able to both run the code from command line with a specific runsettings file and debug by running the script to set my environment variables.

0x4B1D
  • 923
  • 1
  • 9
  • 19
1

Perhaps this is more what you are looking for: How does one debug an MSTest in VSCode?

(also check the comment). So by using "VSTEST_HOST_DEBUG": "1" you should be able to attach a debug process, similar to how one can do it in Java.

Vincent Gerris
  • 7,228
  • 1
  • 24
  • 22