Pau*_*ito 6 c# xunit asp.net-web-api .net-core asp.net-core
我有一个工作的 Web API,最近更新为使用 JWT 身份验证,虽然它在我正常运行时工作,但我似乎无法让我的集成测试工作。
我想开始为我的集成测试集成令牌生成选项,但我什至无法让他们抛出 401。
当我在项目中运行任何无需 JWT 即可工作的现有集成测试时,我预计会收到 401,因为我没有任何身份验证信息,但实际上收到了错误System.InvalidOperationException : Scheme already exists: Bearer。
我认为发生这种情况是因为WebApplicationFactory运行其ConfigureWebHost方法的工作方式在 Startup 类的ConfigureServices方法之后运行,当我在 jwt 服务上放置断点时,它确实会被击中两次,但考虑到这是如何WebApplicationFactory构建的,我不确定这里推荐的选项是什么。值得注意的是,即使我删除其中一项服务,我仍然收到错误:
var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(JwtBearerHandler));
services.Remove(serviceDescriptor);
Run Code Online (Sandbox Code Playgroud)
我的WebApplicationFactory基于 eshopwebapi 工厂:
public class CustomWebApplicationFactory : WebApplicationFactory<StartupTesting>
{
// checkpoint for respawning to clear the database when spinning up each time
private static Checkpoint checkpoint = new Checkpoint
{
};
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Testing");
builder.ConfigureServices(async services =>
{
// Create a new service provider.
var provider = services
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Add a database context (LabDbContext) using an in-memory
// database for testing.
services.AddDbContext<LabDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
options.UseInternalServiceProvider(provider);
});
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database
// context (ApplicationDbContext).
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<LabDbContext>();
// Ensure the database is created.
db.Database.EnsureCreated();
try
{
await checkpoint.Reset(db.Database.GetDbConnection());
}
catch
{
}
}
}).UseStartup<StartupTesting>();
}
public HttpClient GetAnonymousClient()
{
return CreateClient();
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的服务注册:
public static class ServiceRegistration
{
public static void AddIdentityInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = configuration["JwtSettings:Authority"];
options.Audience = configuration["JwtSettings:Audience"];
});
services.AddAuthorization(options =>
{
options.AddPolicy("CanReadPatients",
policy => policy.RequireClaim("scope", "patients.read"));
options.AddPolicy("CanAddPatients",
policy => policy.RequireClaim("scope", "patients.add"));
options.AddPolicy("CanDeletePatients",
policy => policy.RequireClaim("scope", "patients.delete"));
options.AddPolicy("CanUpdatePatients",
policy => policy.RequireClaim("scope", "patients.update"));
});
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的集成测试(我预计当前会抛出 401):
public class GetPatientIntegrationTests : IClassFixture<CustomWebApplicationFactory>
{
private readonly CustomWebApplicationFactory _factory;
public GetPatientIntegrationTests(CustomWebApplicationFactory factory)
{
_factory = factory;
}
[Fact]
public async Task GetPatients_ReturnsSuccessCodeAndResourceWithAccurateFields()
{
var fakePatientOne = new FakePatient { }.Generate();
var fakePatientTwo = new FakePatient { }.Generate();
var appFactory = _factory;
using (var scope = appFactory.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<LabDbContext>();
context.Database.EnsureCreated();
context.Patients.AddRange(fakePatientOne, fakePatientTwo);
context.SaveChanges();
}
var client = appFactory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
var result = await client.GetAsync("api/Patients")
.ConfigureAwait(false);
var responseContent = await result.Content.ReadAsStringAsync()
.ConfigureAwait(false);
var response = JsonConvert.DeserializeObject<Response<IEnumerable<PatientDto>>>(responseContent).Data;
// Assert
result.StatusCode.Should().Be(200);
response.Should().ContainEquivalentOf(fakePatientOne, options =>
options.ExcludingMissingMembers());
response.Should().ContainEquivalentOf(fakePatientTwo, options =>
options.ExcludingMissingMembers());
}
}
Run Code Online (Sandbox Code Playgroud)
嘿,当我寻找相同的答案时,我看到了你的帖子。我通过将以下代码放入 WebApplicationFactory 的 ConfigureWebHost 方法中解决了这个问题:
protected override void ConfigureWebHost(
IWebHostBuilder builder)
{
builder.ConfigureServices(serviceCollection =>
{
});
// Overwrite registrations from Startup.cs
builder.ConfigureTestServices(serviceCollection =>
{
var authenticationBuilder = serviceCollection.AddAuthentication();
authenticationBuilder.Services.Configure<AuthenticationOptions>(o =>
{
o.SchemeMap.Clear();
((IList<AuthenticationSchemeBuilder>) o.Schemes).Clear();
});
});
}
Run Code Online (Sandbox Code Playgroud)
我知道我迟到了四个月,但我希望你仍然有用。
| 归档时间: |
|
| 查看次数: |
2187 次 |
| 最近记录: |