Do you have any examples or pointers on how to get IdentityServer4 and TestServer to work well together? Here's my attempt.
I have an ASP.Net Core project that hosts both MVC and IdentityServer4.
I also have an xunit integration test that uses Microsoft.AspNetCore.TestHost.TestServer to call an MVC action. In the constructor of this test, I'm setting up the HttpClient, and I need to perform the handshake with IdentityServer4 to get a bearer token. However, I'm not having much luck.
Since TestServer creates its own instance of HttpClient, I had to create a new version of IdentityServer4's TestDiscoveryClient which accepts an HttpClient. And this is my resulting code:
`
public class ControllerTests
{
private TestServer _server;
private HttpClient _client;
public ControllerTests()
{
// Arrange
var contentRoot = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\..\..\src\MyApi");
_server = new TestServer(new WebHostBuilder()
.UseContentRoot(contentRoot)
//.UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"))
.UseStartup<Startup>()
);
_client = _server.CreateClient();
// discover endpoints from metadata
var disco = TestDiscoveryClient.GetAsync(_client).Result;
if (disco.IsError)
{
throw new Exception(disco.Error);
}
// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
var tokenResponse = tokenClient.RequestClientCredentialsAsync("api1").Result;
if (tokenResponse.IsError)
{
// ********* THROWS EXCEPTION HERE. Error is "Not Found".
throw new Exception(tokenResponse.Error);
}
_client.SetBearerToken(tokenResponse.AccessToken);
}
[Fact]
public async Task Controller_Test1() // Naming convention <Feature>_<Action>_<State>_<FailureOrSuccess>
{
var response = await _client.PostAsJsonAsync("/api/Test");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal("true", responseString);
}
}
`
This code gets throws an exception because I get a "Not Found" response back from IdentityServer4. I've marked in the code where the exception occurs.
Actually, writing this out helped me figure it out. The key was to use _server.CreateHandler() to create an HttpMessageHandler to pass to both the DiscovertClient constructor and the TokenClient constructor. That means you can't use the DiscoveryClient.GetAsync static method, though.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Actually, writing this out helped me figure it out. The key was to use
_server.CreateHandler()to create anHttpMessageHandlerto pass to both theDiscovertClientconstructor and theTokenClientconstructor. That means you can't use theDiscoveryClient.GetAsyncstatic method, though.