Search code examples
c#moqxunitxunit.netxunit2

getting an error The following constructor parameters did not have matching fixture data: PostgreSqlResource resource


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 .......
    }
}

Solution

  • 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()
        }
    }