asp.net 在创建WebApplicationFactory之后,是否可以模拟服务?

d6kp6zgx  于 2024-01-09  发布在  .NET
关注(0)|答案(1)|浏览(125)

我有一个IntegrationTestHelper类,我用它来创建一个带有模拟InMemory数据库的WebApplicationFactory。

public class IntegrationTestHelper
{
    public WebApplicationFactory<RentAPI.Program> GetWebApplicationFactory(string databaseName)
    {
        var factory = new WebApplicationFactory<RentAPI.Program>().WithWebHostBuilder(builder =>
        {
            builder.ConfigureTestServices(services =>
            {
                var dbContextDescriptor = services.SingleOrDefault(d =>
                    d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));

                services.Remove(dbContextDescriptor);

                services.AddDbContext<ApplicationDbContext>(options =>
                {
                    options.UseInMemoryDatabase(databaseName);
                });
            });
        });

        using var scope = factory.Services.CreateScope(); ;
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
        var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();

        SeedData(userManager, roleManager, db).Wait();

        return factory;
    }
    ...
}

字符串
我在下一个测试中使用GetWebApplicationFactory来获取WebApplicationFactory示例,然后再次使用WithWebHostBuilder来模拟IFilecommunication Service,但它不起作用。API继续使用Program.cs中添加的IFilecommunication Service的实现。

public class PropertyControllerTests
{
    private IntegrationTestHelper _helper;
    private WebApplicationFactory<RentAPI.Program> _factory;
    private HttpClient _client;

    [SetUp]
    public void Setup()
    {
        _helper = new IntegrationTestHelper();
        _factory = _helper.GetWebApplicationFactory(Guid.NewGuid().ToString());
    }

    #region AddNewProperty
    [Test]
    public async Task AddNewProperty_ReturnsOk()
    {
        // Arrange
        _factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureTestServices(services =>
            {
                var fileStorageService = services.SingleOrDefault(d => d.ServiceType == typeof(IFileStorageService));
                services.Remove(fileStorageService);

                var mockedService = new Mock<IFileStorageService>();
                mockedService.Setup(_ => _.UploadFilesAsync(It.IsAny<IFormFile[]>()))
                    .ReturnsAsync(new List<string> { "fileId1", "fileId2" });
                services.AddScoped(_ => mockedService.Object);
            });
        });
        _client = _factory.CreateClient();

        ... // creating and setting data in content

        // Act
        var response = await _client.PostAsync("property/landlord/add", content);

        // Assert
        Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
    }

    [TearDown]
    public void TearDown()
    {
        _client.Dispose();
        _factory.Dispose();
    }
}


但是当我搬家的时候

var fileStorageService = services.SingleOrDefault(d => d.ServiceType == typeof(IFileStorageService));
services.Remove(fileStorageService);

var mockedService = new Mock<IFileStorageService>();
mockedService.Setup(_ => _.UploadFilesAsync(It.IsAny<IFormFile[]>()))
    .ReturnsAsync(new List<string> { "fileId1", "fileId2" });
services.AddScoped(_ => mockedService.Object);


到GetWebApplicationFactory,一切都开始工作了。

public WebApplicationFactory<RentAPI.Program> GetWebApplicationFactory(string databaseName)
{
    var factory = new WebApplicationFactory<RentAPI.Program>().WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            var dbContextDescriptor = services.SingleOrDefault(d =>
                d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));

            services.Remove(dbContextDescriptor);

            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseInMemoryDatabase(databaseName);
            });

            var fileStorageService = services.SingleOrDefault(d => d.ServiceType == typeof(IFileStorageService));
            services.Remove(fileStorageService);

            var mockedService = new Mock<IFileStorageService>();
            mockedService.Setup(_ => _.UploadFilesAsync(It.IsAny<IFormFile[]>()))
                .ReturnsAsync(new List<string> { "fileId1", "fileId2" });
            services.AddScoped(_ => mockedService.Object);
        });
    });

    using var scope = factory.Services.CreateScope(); ;
    var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
    var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
    var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();

    SeedData(userManager, roleManager, db).Wait();

    return factory;
}


它可以工作,但对我来说,这种实现并不方便。
那么,在创建WebApplicationFactory之后,是否可以模拟服务呢?

j0pj023g

j0pj023g1#

如果你检查WithWebHostBuilderCore,你会看到它返回你完全忽略的WebApplicationFactory<TEntryPoint>。尝试使用它:

var newFactory = _factory.WithWebHostBuilder(builder =>
{
    //..
});
// I would recommend to avoid assigning to shared fields in the test
// so the local variable usage
var client = newFactory.CreateClient();

字符串
至于“original”_factory-factory.Services(为种子调用)将在内部初始化测试服务器,这需要从服务集合中构建服务提供者,从注册的Angular 来看,默认服务提供者基本上是只读的(即,您不能添加/删除注册)。

相关问题