简体   繁体   中英

In a dotnet 5 web api project, how do I get the instance of a singleton service in a test method?

I'm integration testing my asp.net 5 web apis. In my test methods I want to get a reference to the instance a of faked service so I can customise the service's behaviour for my tests.

In the app, the service is scoped as singleton.

//in ConfigureServices in Startup.cs    
services.AddSingleton<IYbNewProjectsService, YbNewProjectsService>();

In my test project, I set up my client and server in my TestFixture class, and save a reference to the ServiceProvider, returned to me by the services.BuildServiceProvider() call...

private void SetupClient()
{
    Client = Factory.WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            services.Remove<IYbNewProjectsService>();
            services.AddSingleton<IYbNewProjectsService, FakeYbNewProjetsService>();
        });

        builder.ConfigureServices(services =>
        {
            ServiceProvider = services.BuildServiceProvider();
        });
    })
    .CreateClient(new WebApplicationFactoryClientOptions
    {
        AllowAutoRedirect = false
    });
}

I know it's working, because in my tests, when I do...

// ServiceProvider is inherited from TestFixture, so it's the same as above.
var fakeYbService = (FakeYbNewProjectsService)ServiceProvider.GetService(typeof(IYbNewProjectsService));
fakeYbService.InjectedResponse = @"[{{""idProjet"":1883557,""dateDApplication"":...
var response = await Client.GetAsync("/api/yb-new-projects");

...I get my faked service. Trouble is, when I call Client.GetAsync() , the TestServer is using a clean instance of the same faked service, without my InjectedResponse . This is meant to be a singleton, so why are there two of them?

You don't need to setup a ServiceProvider yourself, it's available on the Factory :

// Use this:
Factory.Services.GetService(typeof(IYbNewProjectsService));

// Instead of:
ServiceProvider.GetService(typeof(IYbNewProjectsService));

It works correctly for me with this setup (.NET 5 Razor pages app + .NET 5 XUnit test project):

// In app Startup.ConfigureServices:
services.AddSingleton<ITestService, TestService>();

// Test
[Fact]
public async Task Test1()
{
    var factory = new WebApplicationFactory<Startup>()
        .WithWebHostBuilder(builder =>
        {
            builder.ConfigureTestServices(services =>
            {
                services.AddSingleton<ITestService, FakeTestService>();
            });
        });

    var svc = factory.Services.GetService<ITestService>();
    svc.Do();

    var client = factory.CreateDefaultClient();

    await client.GetAsync("http://localhost");
}

The endpoint it calls also gets the ITestService and calls the method. In both cases I hit the breakpoint in the FakeTestService .

One thing you could check is that does the Startup.ConfigureServices run before the ConfigureTestServices ? In my case it does which allows us to overwrite the service. If they were to run in the other order, your test service would get overwritten. In this case you would need to use TryAddSingleton instead in your Startup class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM