简体   繁体   English

如何在 do.net 核心测试项目中使用用户机密

[英]How to use user secrets in a dotnet core test project

I want to store a database connection string for my integration tests as a user secret.我想将我的集成测试的数据库连接字符串存储为用户机密。 My project.json looks like this:我的 project.json 看起来像这样:

{
  ...

  "dependencies": {
    ...
    "Microsoft.Extensions.Configuration.UserSecrets": "1.1.0"        
  },

  "tools": {
    "Microsoft.Extensions.SecretManager.Tools": "1.1.0-preview4-final"
  },

  "userSecretsId": "dc5b4f9c-8b0e-4b99-9813-c86ce80c39e6"
}

I've added the following to the constructor of my test class:我已将以下内容添加到测试 class 的构造函数中:

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddUserSecrets();

However when I run the tests the following exception is thrown when it hits that line:但是,当我运行测试时,遇到该行时会抛出以下异常:

An exception of type 'System.InvalidOperationException' occurred in Microsoft.Extensions.Configuration.UserSecrets.dll but was not handled in user code

Additional information: Could not find 'UserSecretsIdAttribute' on assembly 'dotnet-test-nunit, Version=3.4.0.0, Culture=neutral, PublicKeyToken=null'.

Have I missed something or is what I'm trying to do not supported?我是否遗漏了什么或者我试图不支持的是什么?

See instructions in https://patrickhuber.github.io/2017/07/26/avoid-secrets-in-dot-net-core-tests.html , in particular in InitialiseTest add 请参阅https://patrickhuber.github.io/2017/07/26/avoid-secrets-in-dot-net-core-tests.html中的说明,特别是在InitialiseTest中添加

// the type specified here is just so the secrets library can 
            // find the UserSecretId we added in the csproj file
            var builder = new ConfigurationBuilder()
                .AddUserSecrets<HttpClientTests>();

            Configuration = builder.Build()

However note that it will not allow to run tests on build server 但请注意,它不允许在构建服务器上运行测试

You must specify the UserSecretsId in Startup of your application. 您必须在应用程序的Startup中指定UserSecretsId。

[assembly: UserSecretsId("xxx")]
namespace myapp
{
    public class Startup
    {
    ...

Then you have to use the overload of .AddUserSecrets(Assembly assembly) in your test project. 然后,您必须在测试项目中使用.AddUserSecrets(Assembly assembly)的重载。 Example: 例:

.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly)

Source: https://stackoverflow.com/a/40775511/5270073 资料来源: https//stackoverflow.com/a/40775511/5270073

My base test class initializes the ConfigurationBuilder, so knowing the assembly which has the userSecretsId is more tricky.我的基本测试类初始化 ConfigurationBuilder,因此了解具有 userSecretsId 的程序集更加棘手。

However we can determine all the assemblies invoked along the way, as follows但是我们可以确定沿途调用的所有程序集,如下所示

    var builder = new ConfigurationBuilder()
        // NOTE: Make the appsettings optional since we might just have a appsettings.TestConfig
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{environment}.json", optional: true)
        // NOTE: This brings in the test assembly's own settings as overrides for the base and environment values
        .AddJsonFile($"appsettings.TestConfig.json", optional: true)
        .AddEnvironmentVariables();
        
    var currentAssembly = Assembly.GetExecutingAssembly();
    var callerAssemblies = new StackTrace().GetFrames()
        .Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
        .Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName));

    UserSecretsIdAttribute attribute = null;
    foreach (var assembly in callerAssemblies)
    {
        attribute = assembly.GetCustomAttribute<UserSecretsIdAttribute>();
        if (attribute != null)
        {
            break;
        }
    }

    if (attribute != null)
    {
        var userSecrets = attribute.UserSecretsId;

        // Wire up user secrets if we have them
        if (!string.IsNullOrEmpty(userSecrets))
        {
#if NETSTANDARD2_0
            builder.AddUserSecrets(userSecrets);
#else
            builder.AddUserSecrets(userSecrets, false);
#endif
        }
    }

Advantage of this in my scenario is that if the developer assigns user secrets the tests will run locally correctly without any code change on their behalf.在我的场景中这样做的好处是,如果开发人员分配用户机密,则测试将在本地正确运行,而无需代表他们更改任何代码。

The other posts listed here have some great help for doing it all manually but VS2022 has automated it for you.此处列出的其他帖子对手动完成这一切有很大帮助,但 VS2022 已为您自动完成。

In Visual Studio 2022 just right click on the test project name and go to "Manage User Secrets".在 Visual Studio 2022 中,只需右键单击测试项目名称和 go 即可“管理用户机密”。

If you have not installed Microsoft.Extensions.Configuration.UserSecrets it will prompt you that "...dependencies are needed. Would you like to add them..."如果您尚未安装 Microsoft.Extensions.Configuration.UserSecrets,它会提示您“...需要依赖项。您想添加它们吗...”

Click Yes and the secrets.json file will open up and you are off to the races.单击 Yes,secrets.json 文件将打开,您就可以开始比赛了。

(If you already have the UserSecrets installed it just opens up secrets.json.) (如果您已经安装了 UserSecrets,它只会打开 secrets.json。)

Here is a code snippet that worked great for me.这是一个对我非常有用的代码片段。

using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Project.Cosmos;

namespace Project.Model.Tests;

public class CosmosDbRepository
    {
    private IConfiguration Configuration { get; }

    public CosmosDbRepository()
        {
        var builder = new ConfigurationBuilder()
            .AddUserSecrets< CosmosDbRepository >();

        Configuration = builder.Build();
        }

    [Fact]
    public async Task Should_connect_to_cosmos_db()
        {
        // Arrange
        var uri = Configuration[ "Cosmos:Uri" ];
        var key = Configuration[ "Cosmos:Key" ];
        var _repo = await CosmosRepository.CreateRepo( uri, key );
        // Act
        var account = await _repo.Client.ReadAccountAsync();
        // Assert
        account.Should().NotBeNull( "A valid connection should be able to query its account." );
        }
    }

With a secrets.json of用 secrets.json 的

{ "Cosmos": { "Uri": "Your Value Here", "Key": "Your Value Here" } } { "Cosmos": { "Uri": "你的价值在这里", "Key": "你的价值在这里" } }

For settings you can use appsettings.json, not the project.json. 对于设置,您可以使用appsettings.json,而不是project.json。 It looks like this: 它看起来像这样:

{
    "userSecretsId": "dc5b4f9c-8b0e-4b99-9813-c86ce80c39e6"
}

Make sure to copy the file to output by changing the project.json: 确保通过更改project.json将文件复制到输出:

"buildOptions": {
    "copyToOutput": "appsettings.json"
}

Now you can retrieve the secret like this: 现在您可以像这样检索秘密:

[Fact]
public MyTest()
{
    var appSettings = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json")
        .Build();

    var secret = appSettings["userSecretsId"]
}

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

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