Question: xUnit IClassFixture reinitialized for every testcase

I want to write integration tests with shared context (shared state) for all testcases.
From docs:

When using a class fixture, xUnit.net will ensure that the fixture instance will be created before any of the tests have run, and once all the tests have finished, it will clean up the fixture object by calling Dispose, if present.

It follows from docs that I need to use IClassFixture. Ok then.
I create sample ASP .NET Core Web API with controllers and in Program.cs add the only line:
public partial class Program { }

Nothing else is changed in a project.
Then I add xUnit test project where I add reference for my web api project and modify the default UnitTest1 class with the following code:
public class UnitTest1 : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;
    private string? _val;
    public UnitTest1(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public void Test1()
    {
        Assert.Null(_val);
        _val = "smth";
    }

    [Fact]
    public void Test2()
    {
        Assert.NotNull(_val);
    }
}

So basically I want to set "shared context" (which is a string variable in this case) in Test1 and use it in Test2. I run testcases and I see that Test1 passes and Test2 fails.
I have seen xUnit IClassFixture constructor being called multiple times and tried using test explorer window or even switch to Rider but that did not help. Did someone encounter such a behavior?


Answer:
This is working correctly, but you have implemented it wrong. xUnit runtime will create a new instance of UnitTest1 for every test execution, but it should only create a single instance of WebApplicationFactory<Program> for the lifetime of the current test batch execution context for this test class.

Your _val variable is not defined as part of the test fixture at all, so that makes sense that the value is not persisted across the different tests.

Because you are passing the factory, and not the instance, you will experience multiple calls to factory.CreateClient(); and this is expected. In this scenario you wouldn't normally use a factory as the test fixture, but your test fixture could use the factory method internally:
/// <summary>Fixture to share across many tests in the same context</summary>
public class MyTestFixture : IDisposable
{
    public HttpClient Client { get; private set; }
    public string? Value { get; set; }
    
    public MyTestFixture(WebApplicationFactory<Program> factory)
    {
        Client = factory.CreateClient();
    }

    public void Dispose()
    {
        // clean up any unmanaged references
    }
}

* if you are not using DI for your factory, then you should instantiate the factory directly in the constructor instead of expecting it as an argument.
public class UnitTest1 : IClassFixture<MyTestFixture>
{
    private readonly MyTestFixture _sharedContext;

    public UnitTest1(MyTestFixture testFixture)
    {
        _sharedContext = testFixture;
    }

    [Fact]
    public void Test1()
    {
        Assert.Null(_sharedContext.Value);
        _sharedContext.Value = "smth";
    }

    [Fact]
    public void Test2()
    {
        Assert.NotNull(_sharedContext.Value);
    }
}