4

I am using xunit to do integration testing, and below is my test class.

public class CodesAndGuidelinesTest : IClassFixture<SchemaCache>
{
    public readonly SchemaCache schemaCache;
    public CodesAndGuidelinesTest(PostgreSqlResource resource) 
    {
        schemaCache = new SchemaCache(resource);
    }

    [Fact]
    public async Task Create_Name_Contains_Expression()
    {
        IRequestExecutor requestExecutor = await schemaCache.CodesAndGuidelinesExecutor;
        .......
    }
}

Here is the schema cache class

public class SchemaCache : QueryTestBase
{
    Task<IRequestExecutor> _codesAndGuidelinesExecutor;
    public SchemaCache(PostgreSqlResource resource) : base(resource)
    {
        _codesAndGuidelinesExecutor = CreateDb(CodesAndGuidelinesMockFixture.codeStandardGuidelines);
    }

    public Task<IRequestExecutor> CodesAndGuidelinesExecutor
    {
        get { return _codesAndGuidelinesExecutor; }
    }
}

Here CodesAndGuidelinesMockFixture.codeStandardGuidelines is just a mock object, and When I run the test cases, I am getting the below error.

Class fixture type 'API.Tests.SchemaCache` had one or more unresolved constructor arguments: PostgreSqlResource resource, CodeStandardGuideline[] codesAndGuidelines The following constructor parameters did not have matching fixture data: PostgreSqlResource resource

I am not sure where I am doing wrong with the above code. Could anyone point me in the right direction?

Thanks!!!

Update : QueryTestBase class

public class QueryTestBase
{
    private readonly PostgreSqlResource _resource;
    public QueryTestBase(PostgreSqlResource resource)
    {
        _resource = resource;
    }

    protected async Task<Func<IResolverContext, IQueryable<T>>> BuildResolverAsync<T>(T[] arrayOfEntities) where T : class
    {
        var databaseName = Guid.NewGuid().ToString("N");
        var options = new DbContextOptionsBuilder<APIDbContext>()
            .UseNpgsql(_resource.ConnectionString)
            .Options;
        .......
        .......         
        return _ => set.AsQueryable();
    }

    protected async Task<IRequestExecutor> CreateDb<T>(T[] Entities) where T : class
    {
        Func<IResolverContext, IQueryable<T>> resolver = await BuildResolverAsync(Entities);

        return .......
    }
}
Glory Raj
  • 17,397
  • 27
  • 100
  • 203

1 Answers1

2

Your tool (Squadron) provides an easy way to have a PostgreSqlResource.

This resource has this properties:

  • implement standard IDisposable interface (or xunit speficIAsyncLifetime interface)
  • has a parameterless contructor
// sync implementation
class PostgreSqlResource : IDisposable
{
  public PostgreSqlResource()
  {
    // init code
  }

  // props and logic 

  public Dispose()
  {
    // dispose code
  }
}

// async implementation
class PostgreSqlResource : IAsyncLifetime
{
  public PostgreSqlResource()
  {
  }

  public async Task InitializeAsync()
  {
    // init code
  }

  // props and logic 

  public async Task DisposeAsync()
  {
    // dispose code
  }
}

This object can be shared in xunit in 3 way:

  • for each test: create fixture, execute test, dispose fixture
  • for each class: create fixture, execute tests inside a class, dispose fixture
  • for a set of classes: create fixture, execute marked test classes, dispose fixture

In your case you need the 3rd way.

So Squadron provide a fixture for you, jou just need to define a TestCollection to mark your classes.

[CollectionDefinition("Squadron")]
public class DatabaseCollection : ICollectionFixture<PostgreSqlResource>
{
    // This class has no code, and is never created. Its purpose is simply
    // to be the place to apply [CollectionDefinition] and all the
    // ICollectionFixture<> interfaces.
}

and after that you can simply tag your test classes with attribute [Collection("Squadron")] that allow you in inject via constructor the shared instance.

[Collection("Squadron")]
public class DatabaseTestClass1
{
    PostgreSqlResource fixture;

    public DatabaseTestClass1(PostgreSqlResource fixture)
    {
        this.fixture = fixture;
    }
}

[Collection("Squadron")]
public class DatabaseTestClass2
{
   // ...


In case PostgreSqlResource is not enought and you need a more complex fixture is very easy; you can just create your own fixture around the other.

Of course you need to implement the same interface and delegate implementation to inner member.

class ComplexFixture: IAsyncLifetime
{
  private PostgreSqlResource _pg;

  public ComplexFixture()
  {
    _pg = new PostgreSqlResource();
  }

  // fixture methods

  public async Task InitializeAsync()
  {
    await _pg.InitializeAsync();
  }

  public async Task DisposeAsync()
  {
    await _pg.DisposeAsync();
  }
}

And refer to ComplexFixture insted of PostgreSqlResource on xunit CollectionFixtures. This approach is not suggested.


In my opinion is better a Plain fixture injected to test class, and than wrapped in a class fixture object if needed.

[Collection("Squadron")]
public class DatabaseTestClass1 : IDisposable
{
    // each test lifecycle
    private MyComplexFixture _fixture;

                              // global lifecycle
    public DatabaseTestClass1(DatabaseFixture dbFixture)
    {
        _fixture = new MyComplexFixture(dbFixture)
    }

    // tests

    public Dispose()
    {
        // this can reset db state for a new test
        _fixture.Dispose();
    }
}

public class MyComplexFixture : IDisposable
{
    public MyComplexFixture (DatabaseFixture dbFixture)
    {
      // ...
    }

    public Dispose()
    {
       // reset logic like DROP TABLE EXECUTION

       // Please note that dbFixture shoul no be disposed here!
       // xunit will dispose class after all executions.
    }
}

So applying this solution to your code can be as follows.

[CollectionDefinition("SquadronSchemaCache")]
public class DatabaseCollection : ICollectionFixture<SchemaCache>
{
}

[Collection("SquadronSchemaCache")]
public class CodesAndGuidelinesTest
{
    public readonly SchemaCache schemaCache;

    public CodesAndGuidelinesTest(SchemaCache resource) 
    {
        this.schemaCache = schemaCache;
    }

    [Fact]
    public async Task Create_Name_Contains_Expression()
    {
        IRequestExecutor requestExecutor = await schemaCache.CodesAndGuidelinesExecutor;
        .......
    }
}

public class SchemaCache : QueryTestBase
{
    Task<IRequestExecutor> _codesAndGuidelinesExecutor;
    public SchemaCache() : base(new PostgreSqlResource())
    {
        _codesAndGuidelinesExecutor = CreateDb(CodesAndGuidelinesMockFixture.codeStandardGuidelines);
    }

    public Task<IRequestExecutor> CodesAndGuidelinesExecutor
    {
        get { return _codesAndGuidelinesExecutor; }
    }
}

public class QueryTestBase : IAsyncLifetime
{
    private readonly PostgreSqlResource _resource;
    public QueryTestBase(PostgreSqlResource resource)
    {
        _resource = resource;
    }

    protected async Task<Func<IResolverContext, IQueryable<T>>> BuildResolverAsync<T>(T[] arrayOfEntities) where T : class
    {
        var databaseName = Guid.NewGuid().ToString("N");
        var options = new DbContextOptionsBuilder<APIDbContext>()
            .UseNpgsql(_resource.ConnectionString)
            .Options;
        .......
        .......         
        return _ => set.AsQueryable();
    }

    protected async Task<IRequestExecutor> CreateDb<T>(T[] Entities) where T : class
    {
        Func<IResolverContext, IQueryable<T>> resolver = await BuildResolverAsync(Entities);

        return .......
    }

    public async Task InitializeAsync()
    {
      await _resource.InitializeAsync();
    }

    public async Task DisposeAsync()
    {
        _resource.Dispose()
    }
}
Claudio
  • 3,060
  • 10
  • 17
  • Thanks for the explanation. Suppose I want to include these methods `CreateDb` and `BuildResolverAsync`as well in the same class. Where would be the location for that? – Glory Raj Jun 28 '22 at 15:41
  • If you can closely observe, `BuildResolverAsync` is using `resource.connectionstring` coming from `PostgreSqlResource` and If I declare like this `private PostgreSqlResource _pg; public ComplexFixture() { _pg = new PostgreSqlResource(); }` and when I access _pg to get the connection string it is giving me null reference exception – Glory Raj Jun 28 '22 at 15:43
  • Yeah, I need the third option, but I want to include those methods`(CreateDb and BuildResolverAsync)` as well because those are also common among test classes, and those methods need a connection string from `PostgreSqlResource` – Glory Raj Jun 28 '22 at 15:48
  • Could you please give an idea of what will be the `DatabaseFixture` structure will look like in the last option – Glory Raj Jun 28 '22 at 15:55
  • Could you please let me know how it will be a structured for the class `DatabaseFixture` last code you have written in this post I believe you need to define IclassFixture or Icollectionfixture somewhere – Glory Raj Jun 28 '22 at 16:31
  • Last code is using `[Collection("Squadron")]`, so a `CollectionDefinition` class is required as specified in the 2nd snippet. (skipped for brevity). Are you hitting a null reference exception accessing `_pg` variable or one of its properties ? – Claudio Jun 28 '22 at 17:21
  • And I am trying to access the `resource.Connectionstring` is one of its variables because that resource is null. I am getting a null reference exception – Glory Raj Jun 28 '22 at 17:22
  • Could you please elaborate on the last option? It looks like `PostgresqlResource` should be declared as either `IclassFiture<>` or `IcollectionFixture<>` to use the connection string rather than just object initialization like this `class ComplexFixture: IDisposable { private PostgreSqlResource _pg; public ComplexFixture() { _pg = new PostgreSqlResource(); }` – Glory Raj Jun 28 '22 at 17:27
  • I have applied the solution to your code adapting component lifecycle. DB must be created before putting into a xunit Collection, so the fixture is your own. Hope it helps – Claudio Jun 28 '22 at 17:37
  • Sorry the main issue is here `private readonly PostgreSqlResource _resource; public QueryTestBase(PostgreSqlResource resource) { _resource = resource; }` accessing _resource below in class `QueryTestBase` is giving null reference exception – Glory Raj Jun 28 '22 at 17:40
  • with this code, still that issue ? – Claudio Jun 28 '22 at 17:47
  • Yeah it is with the above code – Glory Raj Jun 28 '22 at 17:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/245995/discussion-between-glory-raj-and-claudio). – Glory Raj Jun 28 '22 at 17:56
  • Yeah getting this error in query test base class `System.ArgumentNullException : Value cannot be null. (Parameter 'connectionString')` – Glory Raj Jun 28 '22 at 17:57
  • At this point are you sure that the issue is related to xunit and not to Squadron? I have mocked your storage connection and init connection and the test is green as expected. https://gist.github.com/webartoli/62a03bcfbb84e76ddb8a8ee2614e5f92 – Claudio Jun 28 '22 at 18:05
  • Thanks for the support; I modified it a little bit, combined both querytestbase and schema cache classes, and implemented IAsyncLifetime, and it's working like a charm!!! I will reward the bounty to you before it expires, and once again, thanks for the support. – Glory Raj Jun 28 '22 at 19:44