From 64b6e9ac993cc9b259a557a6f3a8968cbfd51278 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 13 Sep 2025 15:02:35 +0200 Subject: [PATCH 1/3] Support env variables for dotnet test (MTP) --- .../MicrosoftTestingPlatformTestCommand.cs | 6 ++- src/Cli/dotnet/Commands/Test/MTP/Options.cs | 2 +- .../Commands/Test/MTP/TestApplication.cs | 6 +++ .../dotnet/Commands/Test/TestCommandParser.cs | 1 + .../TestProjectShowingEnvVariable/Program.cs | 47 +++++++++++++++++++ .../Properties/launchSettings.json | 10 ++++ .../TestProjectShowingEnvVariable.csproj | 19 ++++++++ .../TestProjectShowingEnvVariable/global.json | 5 ++ .../Test/GivenDotnetTestBuildsAndRunsTests.cs | 30 ++++++++++++ 9 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Program.cs create mode 100644 test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Properties/launchSettings.json create mode 100644 test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj create mode 100644 test/TestAssets/TestProjects/TestProjectShowingEnvVariable/global.json diff --git a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs index 28035134421b..fcc7ed0849ce 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Immutable; using System.CommandLine; using System.Diagnostics.CodeAnalysis; using Microsoft.DotNet.Cli.Commands.Test.Terminal; @@ -41,7 +42,10 @@ private int RunInternal(ParseResult parseResult, bool isHelp) ValidationUtility.ValidateSolutionOrProjectOrDirectoryOrModulesArePassedCorrectly(parseResult); int degreeOfParallelism = GetDegreeOfParallelism(parseResult); - var testOptions = new TestOptions(IsHelp: isHelp, IsDiscovery: parseResult.HasOption(MicrosoftTestingPlatformOptions.ListTestsOption)); + var testOptions = new TestOptions( + IsHelp: isHelp, + IsDiscovery: parseResult.HasOption(MicrosoftTestingPlatformOptions.ListTestsOption), + EnvironmentVariables: parseResult.GetValue(CommonOptions.EnvOption) ?? ImmutableDictionary.Empty); InitializeOutput(degreeOfParallelism, parseResult, testOptions); diff --git a/src/Cli/dotnet/Commands/Test/MTP/Options.cs b/src/Cli/dotnet/Commands/Test/MTP/Options.cs index 21277304d1b9..cb9e29e3e4e3 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/Options.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/Options.cs @@ -3,7 +3,7 @@ namespace Microsoft.DotNet.Cli.Commands.Test; -internal record TestOptions(bool IsHelp, bool IsDiscovery); +internal record TestOptions(bool IsHelp, bool IsDiscovery, IReadOnlyDictionary EnvironmentVariables); internal record PathOptions(string? ProjectPath, string? SolutionPath, string? ResultsDirectoryPath, string? ConfigFilePath, string? DiagnosticOutputDirectoryPath); diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs index 109e9e3b4259..df4a5fff6260 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs @@ -140,6 +140,12 @@ private ProcessStartInfo CreateProcessStartInfo() processStartInfo.Environment[entry.Key] = value; } + // Env variables specified on command line override those specified in launch profile: + foreach (var (name, value) in TestOptions.EnvironmentVariables) + { + processStartInfo.Environment[name] = value; + } + if (!_buildOptions.NoLaunchProfileArguments && !string.IsNullOrEmpty(Module.LaunchSettings.CommandLineArgs)) { diff --git a/src/Cli/dotnet/Commands/Test/TestCommandParser.cs b/src/Cli/dotnet/Commands/Test/TestCommandParser.cs index 229db64e3d75..844e7292dd31 100644 --- a/src/Cli/dotnet/Commands/Test/TestCommandParser.cs +++ b/src/Cli/dotnet/Commands/Test/TestCommandParser.cs @@ -246,6 +246,7 @@ private static Command GetTestingPlatformCliCommand() command.Options.Add(MicrosoftTestingPlatformOptions.MaxParallelTestModulesOption); command.Options.Add(MicrosoftTestingPlatformOptions.MinimumExpectedTestsOption); command.Options.Add(CommonOptions.ArchitectureOption); + command.Options.Add(CommonOptions.EnvOption); command.Options.Add(CommonOptions.PropertiesOption); command.Options.Add(MicrosoftTestingPlatformOptions.ConfigurationOption); command.Options.Add(MicrosoftTestingPlatformOptions.FrameworkOption); diff --git a/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Program.cs b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Program.cs new file mode 100644 index 000000000000..07ba26000ce4 --- /dev/null +++ b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Program.cs @@ -0,0 +1,47 @@ +using Microsoft.Testing.Platform.Builder; +using Microsoft.Testing.Platform.Capabilities.TestFramework; +using Microsoft.Testing.Platform.Extensions.Messages; +using Microsoft.Testing.Platform.Extensions.TestFramework; + +var testApplicationBuilder = await TestApplication.CreateBuilderAsync(args); + +testApplicationBuilder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, __) => new DummyTestAdapter()); + +using var testApplication = await testApplicationBuilder.BuildAsync(); +return await testApplication.RunAsync(); + +public class DummyTestAdapter : ITestFramework, IDataProducer +{ + public string Uid => nameof(DummyTestAdapter); + + public string Version => "2.0.0"; + + public string DisplayName => nameof(DummyTestAdapter); + + public string Description => nameof(DummyTestAdapter); + + public Task IsEnabledAsync() => Task.FromResult(true); + + public Type[] DataTypesProduced => new[] { + typeof(TestNodeUpdateMessage) + }; + + public Task CreateTestSessionAsync(CreateTestSessionContext context) + => Task.FromResult(new CreateTestSessionResult() { IsSuccess = true }); + + public Task CloseTestSessionAsync(CloseTestSessionContext context) + => Task.FromResult(new CloseTestSessionResult() { IsSuccess = true }); + + public async Task ExecuteRequestAsync(ExecuteRequestContext context) + { + var envVariableValue = Environment.GetEnvironmentVariable("DUMMY_TEST_ENV_VAR") ?? "NOT SET"; + await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(context.Request.Session.SessionUid, new TestNode() + { + Uid = "Test1", + DisplayName = "Test1", + Properties = new PropertyBag(new FailedTestNodeStateProperty($"DUMMY_TEST_ENV_VAR is '{envVariableValue}'")), + })); + + context.Complete(); + } +} \ No newline at end of file diff --git a/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Properties/launchSettings.json b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Properties/launchSettings.json new file mode 100644 index 000000000000..8c5035e3252d --- /dev/null +++ b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "ConsoleApp25": { + "commandName": "Project", + "environmentVariables": { + "DUMMY_TEST_ENV_VAR": "FROM_LAUNCHSETTINGS" + } + } + } +} \ No newline at end of file diff --git a/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj new file mode 100644 index 000000000000..192938009781 --- /dev/null +++ b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj @@ -0,0 +1,19 @@ + + + + + $(CurrentTargetFramework) + Exe + + enable + enable + + false + true + --from-run-arguments + + + + + + diff --git a/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/global.json b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/global.json new file mode 100644 index 000000000000..9009caf0ba8f --- /dev/null +++ b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs index 25735f54c6aa..966dbe7a5716 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs @@ -476,5 +476,35 @@ at Microsoft.DotNet.Cli.Commands.Test.TestApplicationActionQueue.Read(BuildOptio result.StdOut.Contains("Test run completed with non-success exit code: 1 (see: https://aka.ms/testingplatform/exitcodes)"); } } + + [Theory] + [InlineData(TestingConstants.Debug)] + [InlineData(TestingConstants.Release)] + public void RunTestProjectWithEnvVariable(string configuration) + { + TestAsset testInstance = _testAssetsManager.CopyTestAsset("TestProjectShowingEnvVariable", Guid.NewGuid().ToString()) + .WithSource(); + + CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) + .WithWorkingDirectory(testInstance.Path) + .Execute( + MicrosoftTestingPlatformOptions.ConfigurationOption.Name, configuration, + CommonOptions.EnvOption.Name, "DUMMY_TEST_ENV_VAR=ENV_VAR_CMD_LINE"); + + if (!TestContext.IsLocalized()) + { + result.StdOut + .Should().Contain("Using launch settings from") + .And.Contain($"Properties{Path.DirectorySeparatorChar}launchSettings.json...") + .And.Contain("Test run summary: Failed!") + .And.Contain("total: 1") + .And.Contain("succeeded: 0") + .And.Contain("failed: 1") + .And.Contain("skipped: 0") + .And.Contain("DUMMY_TEST_ENV_VAR is 'ENV_VAR_CMD_LINE'"); + } + + result.ExitCode.Should().Be(ExitCodes.Success); + } } } From 83863f9d49262e453d9726d1137492a46ad4d57b Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Sat, 13 Sep 2025 15:05:03 +0200 Subject: [PATCH 2/3] Fix test --- .../TestProjectShowingEnvVariable.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj index 192938009781..1ba237591546 100644 --- a/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj +++ b/test/TestAssets/TestProjects/TestProjectShowingEnvVariable/TestProjectShowingEnvVariable.csproj @@ -10,7 +10,6 @@ false true - --from-run-arguments From 93b1c1e22a84b8147c1064deda325329f24d2968 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Sat, 13 Sep 2025 17:05:16 +0200 Subject: [PATCH 3/3] Fix test assertion --- .../CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs index 966dbe7a5716..29ca6c1a0825 100644 --- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs +++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs @@ -504,7 +504,7 @@ public void RunTestProjectWithEnvVariable(string configuration) .And.Contain("DUMMY_TEST_ENV_VAR is 'ENV_VAR_CMD_LINE'"); } - result.ExitCode.Should().Be(ExitCodes.Success); + result.ExitCode.Should().Be(ExitCodes.AtLeastOneTestFailed); } } }