These steps are for getting .NET Core 2.1 MSTest tests to support building up the environment variables that an Azure Function uses both in a local environment and in Azure DevOps CI.
- Need to use live resources for integration testing because Event Hub doesn't have an emulator
- This means I have connection strings that must be treated like secrets (can't use
UseDevelopment=truefor everything)
- This means I have connection strings that must be treated like secrets (can't use
- Can't easily build up my own configuration using
ConfigurationBuilderin the application because I'm using Azure Functions (and Webjobs)- Can't use something like this
- Need to be able to run locally and in Azure DevOps (VSTS)
// Azure Function
public static class Endpoint
{
private static string EhConnectionString { get; } =
Environment.GetEnvironmentVariable("EventHubConnectionString");
[FunctionName("Endpoint")]
public static async Task<IActionResult> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "post")]HttpRequest request, ILogger log)
{ /* do cool stuff */ }
}
// test fixture
[TestClass]
public class EndpointTests : FunctionTest
{
[TestInitialize]
public void Setup()
{
var settings = new ConfigurationBuilder()
.AddJsonFile("appsettings.test.json", false)
.Build();
foreach (var item in settings.AsEnumerable())
{
Environment.SetEnvironmentVariable(item.Key, item.Value);
}
}
// test methods
}// local appsettings.test.json that is also gitignored
{
"EventHubConnectionString": "<ConnectionString>"
}- Added Variable Group that included secrets
- Add
dotnet buildtask to build definition (afterdotnet restoretask) with:- "Arguments" field:
--no-restore --output $(Build.BinariesDirectory)
- "Arguments" field:
- Add File Creator task to build definition (after
dotnet buildtask) with:- "File path" field:
$(Build.BinariesDirectory)\appsettings.test.json - "File content" field:
{ "EventHubConnectionString": "$(EventHubConnectionString)", } - "File path" field:
- Add
dotnet testtask to run only integration test project within solution with:- "Arugments" field:
--no-restore --no-build --output $(Build.BinariesDirectory)
- "Arugments" field:
So final task list was:
dotnet restoredotnet build- File Creator
dotnet test(integration test)
RUNSETTING ARGUMENTS DO NOT WORK AT ALL WITH DOTNET TEST (see open issue)
- Add
*.runsettingsfile containing non-sensitive config to add to environment variables - Add test setup code that iterates through
TestContext#Propertiesand sets environment variables
<!--mysettings.runsettings-->
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<TestRunParameters>
<Parameter name="AzureWebJobsStorage" value="UseDevelopmentStorage=true" />
<Parameter name="MyNonSensitiveEnvVarSetting" value="foobar" />
</TestRunParameters>
</RunSettings>// test fixture
public TestContext TestContext { get; set; }
[TestInitialize]
public void Setup()
{
foreach (var item in TestContext.Properties)
{
Environment.SetEnvironmentVariable(item.Key.Replace(EnvVarPrefix, string.Empty), item.Value.ToString());
}
}
I know this is not a forum, but anyway I would like to mention my findings about this strategy, focusing on the DevOps part.
As far as I could see, the
--no-restore --no-buildparameters are not needed.The
--outputparameter is only there to make sure all steps work in the same directory. For some reason that I could not resolve, in my solution some project dependencies are not found when I use the explicit output directory. Therefore my solution was to identify the default working directory of my test step and to create the appsettings file right there. Not beautiful, but working.