简体   繁体   English

将参数传递给 dotnet 测试项目?

[英]Passing arguments to dotnet test project?

I have the test class below in a .NET Core 1.1 Unit Test project (not an xUnit Test project) in Visual Studio 2017. How do I pass command line arguments to TestMethod ?我在 Visual Studio 2017 的 .NET Core 1.1 单元测试项目(不是 xUnit 测试项目)中有下面的测试类。如何将命令行参数传递给TestMethod

[TestClass]
public class TestClass
{
    [TestMethod]
    public void TestMethod()
    {
        var args = Environment.GetCommandLineArgs();
        var json = JsonConvert.SerializeObject(args);
        throw new Exception(json);
    }
}

Lots of places on the internet make it sound like you can just put a -- in front of the arguments you want to pass in, but I can't get it to work.互联网上的很多地方听起来好像你可以在你想要传递的参数前面放一个-- ,但我无法让它工作。

These are the commands I've tried:这些是我尝试过的命令:

  • dotnet test TestProject.csproj -- hello=world
  • dotnet test TestProject.csproj -- --hello world
  • dotnet test TestProject.csproj -- -hello world

But all of them output this message every time.但是他们每次都输出这个消息。 Note how neither hello nor world are present:请注意helloworld都不存在:

["C:\\Users\\____\\.nuget\\packages\\microsoft.testplatform.testhost\\15.0.0\\lib\\netstandard1.5\\testhost.dll","--port","55032","--parentprocessid","24440"] ["C:\\Users\\____\\.nuget\\packages\\microsoft.testplatform.testhost\\15.0.0\\lib\\netstandard1.5\\testhost.dll","--port","55032","--parentprocessid" ,"24440"]

The first string is just the name of the running assembly -- pretty standard for the first command line argument .第一个字符串只是正在运行的程序集的名称—— 第一个命令行参数非常标准 I don't know where the --port or --parentprocessid arguments are coming from.我不知道--port--parentprocessid参数来自哪里。

Also, these variations make dotnet test choke with One or more runsettings provided contain invalid token (sic):此外,这些变化使dotnet test窒息,提供的One or more runsettings provided contain invalid token (原文如此):

  • dotnet test TestProject.csproj -- -hello=world
  • dotnet test TestProject.csproj -- --hello=world

Edit: It looks like GetCommandLineArgs() isn't that great of an option , even if it did work here.编辑:看起来GetCommandLineArgs()并不是一个很好的选项,即使它在这里确实有效。

Also, the answer to this question on social.msdn.microsoft.com from 2006 says:此外, 2006 年在 social.msdn.microsoft.com 上对这个问题的回答说:

The way those classes are instantiated so VS can do unit testing against them is entirely different than normal execution.实例化这些类以便 VS 可以对它们进行单元测试的方式与正常执行完全不同。 The executable is not run like normal, and neither you nor VS can provide arguments to it .可执行文件不像正常运行,您和 VS 都不能为其提供参数 The classes are instantiated indepdently of program execution by using the binary as a class library.通过使用二进制文件作为类库,这些类独立于程序执行进行实例化。 (sic) (原文如此)

I wonder if this still applies to dotnet test ?我想知道这是否仍然适用于dotnet test

In other news, this guy on SO was doubtful that command line arguments could be passed to DLLs at all, but he's wrong :在其他新闻中, SO 上的这个人怀疑命令行参数是否可以传递给 DLL,但他错了

[Prototype for the <entrypoint> function:] void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine , int nCmdShow); [<entrypoint> 函数的原型:] void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine , int nCmdShow);

[Rundll] calls the <entrypoint> function, passing the command line tail which is the <optional arguments>. [Rundll] 调用<entrypoint> 函数,传递命令行尾部,即<可选参数>。

This is one of the places I encountered while searching for this answer, so it's only fair I share my workaround here.这是我在寻找这个答案时遇到的地方之一,所以我在这里分享我的解决方法是公平的。

At this moment, there is no way to pass parameters to any .net test project.目前,没有办法将参数传递给任何 .net 测试项目。 You could use the mstest testsettings/runsettings file, but that requires creating seperate files.您可以使用 mstest testsettings/runsettings 文件,但这需要创建单独的文件。 In my case, I needed a servername and a password for my Selenium Coded UI tests, and I did not want to store them.就我而言,我的 Selenium Coded UI 测试需要服务器名和密码,但我不想存储它们。

One of the recommended ways of passing parameters, is through environment variables.推荐的参数传递方式之一是通过环境变量。 So in your C# xunit file, you can do something like:因此,在您的 C# xunit 文件中,您可以执行以下操作:

// in mytest.cs
var user = Environment.GetEnvironmentVariable("TestUser");
var password = Environment.GetEnvironmentVariable("TestPassword");
var url = Environment.GetEnvironmentVariable("TestUrl");

If you do not want to definitively set your environment variables, remember you can always set them temporarily for just your session process.如果您不想明确设置您的环境变量,请记住您始终可以仅为您的会话进程临时设置它们。 One way of doing this, is by creating a simple cmd file一种方法是创建一个简单的 cmd 文件

#launchtests.cmd
SETLOCAL
SET TestUser='pete001'
SET TestPassword='secret'
SET TestUrl='http://testserver.local/login'
DOTNET TEST mytest.csproj

And now the fun part.现在是有趣的部分。 You can parameterize every aspect of this.您可以参数化此的每个方面。 So you can change it to:所以你可以把它改成:

#run wity launchtests.cmd pete001 secret 'http://testserver.local/login'
SETLOCAL
SET %1
SET %2
SET %3
DOTNET TEST mytest.csproj

Or if you want to launch the test from an Azure DevOps (fka VSTS or TFS) pipeline, you can simply use the $(...) notation to inline variables, even if they're marked secret and/or come from Azure KeyVault.或者,如果您想从 Azure DevOps(fka VSTS 或 TFS)管道启动测试,您可以简单地使用 $(...) 表示法来内联变量,即使它们被标记为机密和/或来自 Azure KeyVault .

#In AzureDevops, variables not marked as secret are already added to the environment
SET TestPassword=$(TestPassword)
dotnet test $(Build.SourcesDirectory)\MyCompany.MyProduct.UITests\MyTest.csproj --configuration $(BuildConfiguration) --collect "Code Coverage" --logger trx --results-directory $(Agent.TempDirectory)

运行 Azure DevOps 命令任务

You can pass Runsettings to the test runner like this (example for bash):您可以像这样将 Runsettings 传递给测试运行器(例如 bash):

dotnet test PathToYourTestProject.dll -- 'TestRunParameters.Parameter(name="YourTestProject.Args",value="ServiceConfig:BaseAddress=http://localhost:8080 ServiceConfig:MaxMemory=2048")'

For other shell types this is obviously a question of correct escaping which might be a pain as you will see.对于其他 shell 类型,这显然是一个正确转义的问题,正如您将看到的那样,这可能会很痛苦。 For MSTest the parameters are accessible via对于 MSTest,参数可通过

var args = TestContext.Properties["YourTestProject.Args"].Split();

I think I'm going about this all wrong.我想我对这一切都错了。 A blend of the below two things is probably the best approach.结合以下两件事可能是最好的方法。

Option 1: Refactor from integration tests into unit tests选项 1:从集成测试重构为单元测试

TestMethod as it is now is an integration test, not a unit test, because it depends on command line arguments. TestMethod现在是一个集成测试,而不是单元测试,因为它依赖于命令行参数。

If I refactor TestMethod so that it gets the command line arguments from an interface like this:如果我重构TestMethod以便它从这样的界面获取命令行参数:

interface IArgumentsProvider
{
    IEnumerable<string> GetArguments();
}

...then this transforms TestMethod into a unit test, where IArgumentsProvider can be mocked, so that only the functionality within TestMethod is tested (that's the definition of a unit test). ...然后这将TestMethod转换为单元测试,其中IArgumentsProvider可以被IArgumentsProvider ,以便只测试TestMethod的功能(这是单元测试的定义)。

Note that I'd probably want to then move tests on the non-mocked implementation of that interface to where the other integration tests are.请注意,我可能希望然后将该接口的非模拟实现上的测试移动到其他集成测试所在的位置。 See below.见下文。

Option 2: Move integration tests out of Unit Test projects to elsewhere in deployment pipeline选项 2:将集成测试从单元测试项目移到部署管道中的其他地方

It isn't always possible to refactor a test into a unit test.将测试重构为单元测试并不总是可能的。 For example, at some point you're going to want to guarantee that a Location controller can actually post and retrieve geo-coordinates from a SQL database before releasing the code into the wild.例如,在某些时候,您需要保证位置控制器可以在将代码发布到野外之前实际发布和检索 SQL 数据库中的地理坐标。

That's an example of an integration test.这是集成测试的一个例子。 And integration tests belong elsewhere in the deployment pipeline: instead of having the test execute as part of the build definition within a Unit Test project, move it into the release definition and invoke it from a more proper framework.集成测试属于部署管道中的其他地方:不要将测试作为单元测试项目中构建定义的一部分来执行,而是将其移动到发布定义中并从更合适的框架中调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM