Use secrets in unit tests
Although the majority of "unit tests" should adhere to the "FIRST" characteristics and be "isolated" by mocking out their dependencies, there are occasions where it can be useful to actually connect to an external resource, allowing you to use a unit test runner to exercise your code against a "real" dependency.
I recently wanted to do this to for some code that accessed Azure Table Storage. The existing code was performing poorly and used an old SDK, and so I wanted to fully cover it with "integration tests" before upgrading to the new SDK and performance tuning it.
To do so, I needed access to a connection string, but didn't want to hard-code it as we all know that secrets don't belong in source control. Of course an obvious solution would be to access the connection string as an environment variable, but the Visual Studio Test Explorer (as far as I can tell at least) offers no easy way to set environment variables for a test run.
Note: there is a .runsettings
file but that suffers from exactly the same problem - you'd end up checking secrets into source control.
Fortunately, the .NET user secrets feature can help us out here. And although many articles about it assume you're using ASP.NET Core, you can use .NET user secrets in any project type, including an NUnit test assembly.
The steps are simple. First, in a command prompt in the directory of your unit test project, enter the dotnet user-secrets init
command. This adds a UserSecretsId
GUID into your .csproj
file.
Then you can store your secret with the dotnet user-secrets set
command. For example:
dotnet user-secrets set MyConnectionString "Your connection string goes here"
Using the secret value within your unit test is very simple. Just use a ConfigurationBuilder
and call AddUserSecrets
using any class from your assembly as the generic argument. Then you can access secrets by name on the configuration instance, and you'll get a null value if the secret is not present.
using Microsoft.Extensions.Configuration;
// ...
var config = new ConfigurationBuilder()
.AddUserSecrets<MyUnitTests>()
.Build();
var connectionString = config["MyConnectionString"];
Note that you will need the Microsoft.Extensions.Configuration.UserSecrets
NuGet package for this to work, which you can install with:
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
Anyway, although I'm sure many of my readers already know about user secrets, I wanted to document how to use them, as I still very often see secrets hard-coded in unit tests.
Update: Thanks to a comment from Vladislav Antonyuk, I realised after posting this that I hadn't said anything about how you'd access secrets if you were running the tests in a CI/CD environment (as I was mainly focusing on the challenge of running them in the VS Test Explorer without committing secrets to source control). In a CI/CD situation I'd simply use environment variables. Just add an .AddEnvironmentVariables()
call to the ConfigurationBuilder
.