У меня проблема с моим .Net Core API, где я использую Azure AD B2C (токены на предъявителя). Приложение работает просто отлично, но я также хотел написать модульный тест, например, для простого GET. Я получаю следующую ошибку при выполнении теста:
System.Net.Http.HttpRequestException : Error while copying content to a stream.
---- System.IO.IOException :
-------- System.InvalidOperationException : IDX20803: Unable to obtain configuration from: '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'.
------------ System.IO.IOException : IDX20804: Unable to retrieve document from: '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'.
---------------- System.Net.Http.HttpRequestException : Response status code does not indicate success: 404 (Not Found).
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at Ttpsc.DotNetInternship.SandwichApp.Tests.InMemory.Base.BaseTest.Get[T](String endpoint, T parameter) in C:\...SandwichApp.Tests\InMemory\Base\BaseTest.cs:line 90
at C:\..SandwichApp.Tests.ControllersTest.GroupsControllerTest.GetGroups_GetAllGroups() in C:\..SandwichApp.Tests\ControllersTest\GroupsControllerTest.cs:line 20
--- End of stack trace from previous location where exception was thrown ---
----- Inner Stack Trace -----
at Microsoft.AspNetCore.TestHost.ResponseStream.CheckAborted()
at Microsoft.AspNetCore.TestHost.ResponseStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
at System.IO.Stream.CopyToAsyncInternal(Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
----- Inner Stack Trace -----
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.TestHost.HttpContextBuilder.<>c__DisplayClass10_0.<<SendAsync>b__0>d.MoveNext()
----- Inner Stack Trace -----
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
----- Inner Stack Trace -----
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
BaseTest.CS (Создать TestServer и HttpClient.Client)
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Flurl.Http;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Newtonsoft.Json.Linq;
namespace Ttpsc.DotNetInternship.SandwichApp.Tests.InMemory.Base
{
public abstract class BaseTest : IDisposable
{
private bool _disposed;
protected BaseTest()
{
Server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
Services = Server.Host.Services;
Client = Server.CreateClient();
//Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
protected TestServer Server { get; set; }
protected HttpClient Client { get; set; }
protected IServiceProvider Services { get; set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected Task<HttpResponseMessage> Get(string endpoint)
{
return Get<string>(endpoint, null);
}
protected async Task<HttpResponseMessage> Get<T>(string endpoint, T parameter)
{
var tt = await GetToken();
var jo = JObject.Parse(tt);
var token = jo["access_token"].ToString();
Client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
var url = string.Concat(endpoint, parameterQuery);
Console.WriteLine(url);
return await Client.GetAsync(url);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
if (disposing)
{
Client?.Dispose();
Server?.Dispose();
}
_disposed = true;
}
}
}
GroupsControllerTest.CS (модульный тест)
using System.Net;
using System.Threading.Tasks;
using Ttpsc.DotNetInternship.SandwichApp.Tests.InMemory.Base;
using Xunit;
namespace Ttpsc.DotNetInternship.SandwichApp.Tests.ControllersTest
{
public class GroupsControllerTest : BaseTest
{
[Fact]
public async Task GetGroups_GetAllGroups()
{
// Arrange
var url = "api/groups";
var expected = HttpStatusCode.OK;
// Act
var response = await Get(url);
// Assert
Assert.Equal(expected, response.StatusCode);
}
}
}