Recently I wanted to test my new ASP.NET Core MVC app, so that I can be sure my startup.cs
configuration is correct, and especially focusing on the JSON parsing of it.
I straight away run into a few basic stumbling blocks that might help a few people out there!
Test Discovery
The first stumbling block was trying to get the tests discovered at all.
I had to select a test runner and add this to the root of my project.json
:
{
"testRunner": "xunit",
....
}
I tried to initially use xunit
and dotnet-test-xunit
versions 2.1.0
which is the officially released version at the time of writing.
But as this does not support Microsoft.NETCore.App 1.0.1
, after a bit off Bing’ing around, I figured out that I need to use "dotnet-test-xunit": "2.2.0-preview2-build1029"
Referencing the MVC Project
The second stumbling block was trying to simply reference the MVC project, in this case, “Taskily”. So I added the following line:
"dependencies": {
.....
"Taskily": "1.0.0*"
}
But this was giving me a “runtimes” is an unsupported framework
error, which I couldn’t for the life of me figure out. In the end, it turned out to be that because the Taskily
project (or at least it was called Taskily in the .sln) actually resided in a folder called WebApplication1
so my solution structure looked like this
root
|global.json
|---src
|---WebApplication1 <-- renamed to Taskily in .sln
|---Taskily.Tests <-- new test project
The way I got this to compile is
- Close the .sln
- Rename
WebApplicaiton1
folder toTaskily
(same as project name in.sln
) - Re-Open
.sln
(Taskily
won’t load as it is looking forsrc/WebApplication1/Taskily.xproj
- Remove the reference to the
Taskily
project from the.sln
. - Re-Add the
Taskily
project which should now be insrc/Taskily/Taskily.xproj
- Compile
The error message was so not intuitive,and was bugging me for ages!
MVC Integration Test
Next, I needed to somehow integrate the startup configuration, which contains the JSON.Net
serializer settings, etc. in my tests so I followed the Microsofts Integration Testing Article which allows you to create an in memory host of your MVC app with custom such as the following:
public class ApiTests
{
private readonly HttpClient _client;
public ApiTests()
{
var server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
);
_client = server.CreateClient();
}
[Fact]
public async void Get_Returns2Values()
{
var response = await _client.GetAsync("https://localhost/api/Alexa/");
var res = await response.Content.ReadAsStringAsync();
res.Should().Be(@"[""value1"",""value2""]");
}
}
In order for this to run, I had to add the following NuGet package dependency in order to be able to use the AspNetCore TestServer
class.
"Microsoft.AspNetCore.TestHost": "1.1.0-preview1-final",
UserSecrets
This allowed me to compile and run the test, but straight away the test failed as I was using UserSecrets
, as specified in Microsoft’s Safe storage of app secrets during development article, and one of my Middleware was throwing an exception that the value cannot be null.
So I added a user secrets Id into the test project.json
:
{
....
"userSecretsId": "aspnet-WebApplication1-19b75b8b-b10e-4fea-94e8-17c9f955732e"
}
and also added the SecretManager tool into the project via project.json which allows me to manage the user secrets for the project via command line:
{
.....
"tools": {
"Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final"
},
.....
}
I then set my 2 user secrets that one of my AspnetCore middleware’s needed by
- dotnet restore (
Ctrl
+Shift
+K
,Ctrl
+Shift
+R
in VS on the project) - Open Command Prompt in the test folder
run the following command
dotnet user-secrets set ClientID MySecretClientIdValue dotnet user-secrets set ClientIDPassword PasswordThatYouWillNeverGuess
Environment
Now that the UserSecrets were setup, my test was still failing with the same error (that the ClientID
is null
, which is retrieved from UserSecrets
).
After a bit of digging around I noticed the following:
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
which meant, that ASP.NET Core will only use UserSecrets when the server is running in Development environment. I could change this but it’s probably like that for a reason! So instead decided to set the environment variable on the TestServer
by using the WebHostBuilder
like the following:
var server = new TestServer(new WebHostBuilder()
.UseEnvironment(EnvironmentName.Development) //<-- Setting Environment Variable
.UseStartup<Startup>()
);
Now my test was running successfully and Bobs your uncle! 😀
Happy Coding