7

I'm currently working on a .net core solution (multiple projects) that uses Microsoft's app secrets management. I can pull secrets back in my runtime project (e.g. Console app), but when it comes to leveraging user secrets for integration tests in a separate project (e.g. Model.Test project), what's the right approach?

I can think of a few options:

  1. Give each project the same UserSecretsId: This seems like it'd made sense for test projects that may leverage the same secrets that the runtime project uses.

  2. Let each project have unique UserSecretsId: This would require that the secrets be manually kept in sync on the development machine

It seems like even between .net core 1.0 and 2.0 user secrets has changed somewhat and I don't have a lot of familiarity with this system in general. Thanks!

Killnine
  • 5,728
  • 8
  • 39
  • 66

2 Answers2

9

I’m still learning about configuration in .NET Core 2 myself. When I set up my API project I shared the user secrets tag between the project and the unit test project by copying it between them. Meaning they both had the same user secrets guid, like your option 1. My rationale is that it would be the easiest way to maintain secrets between the two projects for the development team.

This article from Patrick Huber shows how to reference User Secrets in the config builder which was key for me - https://patrickhuber.github.io/2017/07/26/avoid-secrets-in-dot-net-core-tests.html

This article from Rick Strahl was also useful it shows how to configure a test helper in your unit tests for accessing the user secrets: https://weblog.west-wind.com/posts/2018/Feb/18/Accessing-Configuration-in-NET-Core-Test-Projects

Related implementation question - How to use user secrets in a dotnet core test project

Question related to referencing the config file - AppSettings.json for Integration Test in ASP.NET Core

Dale C
  • 567
  • 6
  • 9
4

This provides a concrete example using the references that Dale C provided to this question earlier.

It has been tested with .NET6. The example will load configuration from

  • appsettings.json
  • secrets.json
  • Environment variables

Create a test project

In your test project

  1. Add nuget package Microsoft.Extensions.Configuration.UserSecrets
  2. In the .csproj file of our test project, add the guid of the user secret we want to access.
<PropertyGroup>
    <UserSecretsId>0e8ea027-2feb-4098-ba69-4a6711e8eee2</UserSecretsId>
</PropertyGroup>
  1. Create a test class
using NUnit.Framework;
using MediatR;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;


namespace Example
{
    public class ConfigurationExampleTest
    {
        public IMediator? _mediator { get; set; }
        public IConfiguration config { get; set; }

        [SetUp]
        public void Setup()
        {            
            // The startupPath is simply one way of getting the path to
            // appettings.json. We could hard code tha path if necessary
            // or use any other method to obtain the path to appsettings.json
            var filepath = typeof(WebApp.Startup)
                .Assembly.Location;
            var StartupPath = Path.GetDirectoryName(filepath);

            config = new ConfigurationBuilder()
                .SetBasePath(StartupPath)
                .AddJsonFile("appsettings.json", optional: true)
                .AddUserSecrets<ConfigurationExampleTest>()
                .AddEnvironmentVariables()
                .Build();

           
            var host = Host.CreateDefaultBuilder()
                .ConfigureWebHostDefaults(builder =>
                {
                    builder.UseStartup<WebApp.Startup>();
                })
                .ConfigureServices(services =>
                {
                    // Adds the config to the dependency injection
                    // This makes the config object accessible in
                    // your WebApp/project-under-test
                    services.AddSingleton(config);
                })
                .Build();
             
             // This will get any service we added to the dependency injection
             // in WebApp.Startup
            _mediator = host.Services.GetService<IMediator>();
        }

        [TearDown]
        public void Teardown()
        { }

        [Test]
        public void ExampleTest()
        {            
            // The configuration object will now be available
            // vai dependency ibjection

            // We can use the_mediator instance we got from the
            // dependency injection here
            
            // _mediator.Send(<your request>);
            
        }
    }
}

References:

kkuilla
  • 2,226
  • 3
  • 34
  • 37