unit-testingsecurity.net-core

.NET Core 2.0 User Secrets and Unit Testing


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!


Solution

  • 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

    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: