使用WebApplicationFactory模拟替换服务

Ban*_*San 3 .net razor asp.net-core

我试图替代的实现IMessageFormatterMockMessageFormatter一个测试。

public class MyMockingWebApplicationFactory<TStartUp> : WebApplicationFactory<Startup>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services => { services.AddTransient<IMessageFormatter, MockMessageFormatter>(); });
    }
}
Run Code Online (Sandbox Code Playgroud)

测试看起来像这样:

public class MockingTests : IClassFixture<MyMockingWebApplicationFactory<Startup>>
{
    public MockingTests(MyMockingWebApplicationFactory<Startup> webApplicationFactory)
    {
        _webApplicationFactory = webApplicationFactory;
    }

    private readonly MyMockingWebApplicationFactory<Startup> _webApplicationFactory;

    [Fact]
    public async Task MockIt()
    {
        var client = _webApplicationFactory.WithWebHostBuilder(builder =>
        {
            //builder.ConfigureServices(services =>
            //{
            //    var foo = ServiceDescriptor.Transient<IMessageFormatter, MessageFormatter>();
            //    services.Remove(foo);
            //    services.AddTransient<IMessageFormatter, MockMessageFormatter>();
            //});
        }).CreateClient();

        var message = "Hello";
        var expectedReversedMessage = "foo";
        var result = await client.GetAsync($"/?message={message}");
        var content = await result.Content.ReadAsStreamAsync();
        var htmlParser = new HtmlParser();
        var htmlDocument = await htmlParser.ParseAsync(content);
        var messageElement = htmlDocument.GetElementById("original-message");
        var reversedMessageElement = htmlDocument.GetElementById("reversed-message");
        Assert.Equal(message, messageElement.InnerHtml);
        var reversedMessage = reversedMessageElement.InnerHtml;
        Assert.Equal(expectedReversedMessage, reversedMessage);
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试将调用添加到ConfigureServices客户端和中,MyMockingWebApplicationFactory但是问题似乎是真正的 Startup类在测试注册后执行,因此覆盖了它们。

真正的 StartUp类是:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); ;
        services.AddTransient<IMessageFormatter, MessageFormatter>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseDeveloperExceptionPage();
        app.UseMvc();
    }
}
Run Code Online (Sandbox Code Playgroud)

Roa*_* S. 16

老问题,只是使用 ASP.NET Core 2.1 及更高版本时当前最佳实践的更新。使用 ASP.NET Core 5 进行测试。

services.AddTransient下面的代码中将替换IMessageFormatter容器中的现有实例。

var client = _webApplicationFactory.WithWebHostBuilder(
    builder => builder.ConfigureTestServices(
        services => services.AddTransient<IMessageFormatter, MockMessageFormatter>()))
    .CreateClient();
Run Code Online (Sandbox Code Playgroud)

如果您需要从容器中检索测试期间插入的服务:

var factoryWithMockService = _webApplicationFactory.WithWebHostBuilder(
    builder => builder.ConfigureTestServices(
        services => services.AddTransient<IMessageFormatter, MockMessageFormatter>()));

var client = factoryWithMockService.CreateClient();
var mockService = factoryWithMockService.Services.GetRequiredService<IMessageFormatter>();
Run Code Online (Sandbox Code Playgroud)

使用起订量时:

var messageFormatterMock = new Mock<IMessageFormatter>();
messageFormatterMock.Setup(svc => svc...).Returns(...);

var client = _webApplicationFatory.WithWebHostBuilder(
    builder => builder.ConfigureTestServices(
        services => services.AddTransient(_ => messageFormatterMock.Object)))
    .CreateClient();

...

messageFormatterMock.Verify(svc => svc..., ...);

Run Code Online (Sandbox Code Playgroud)

有关更多详细信息:https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests ?view=aspnetcore-5.0#inject-mock-services


yay*_*hei 6

替换您的代码:

builder.ConfigureServices(services => { services.AddTransient<IMessageFormatter, MockMessageFormatter>(); });
Run Code Online (Sandbox Code Playgroud)

至:

builder.ConfigureTestServices(services =>
        {
            var serviceProvider = services.BuildServiceProvider();
            var descriptor =
                new ServiceDescriptor(
                    typeof(IMessageFormatter),
                    typeof(MockMessageFormatter),
                    ServiceLifetime.Transient);
            services.Replace(descriptor);
        });
Run Code Online (Sandbox Code Playgroud)