How to parametrize a xunit class fixture?

别等时光非礼了梦想. 提交于 2021-02-20 18:42:29

问题


xUnit offers the concept of (shared) class fixtures as explained in Shared Context between Tests. What I didn't figure out so far is if there is a way of parametrizing such class fixtures. For example, what if the DatabaseFixture should be enriched with some test data which depends on the test it's being run against? A test class might want to insert test data but only once and then run all its tests against that database (fixture).

In other words, what if the // ... initialize data in the test database ... from the documentation (referenced above) also depends on the test? Because not all tests might want to have the same test data. Actually, I even think that many times it's good practice that tests define their own test data to not couple tests on the level of test data.

What I'm doing so far as workaround is to offer a ConfiguredWith method that takes in a callback that is only being executed once. And in order to do so, I need to lazily postpone the initialization of the test database so that I'm sure that the configuration options are set. Something like:

public class MyDatabaseTests : IClassFixture<DatabaseFixture>
{
    DatabaseFixture fixture;

    public MyDatabaseTests(DatabaseFixture fixture)
    {
         this.fixture = fixture;
         this.fixture.ConfigureWith(new DatabaseFixtureOptions
         {
             InitTestData = db => db.Insert(...);
         };
    }

    // ... 
}

And this looks rather contrived for something that feels like a standard requirement when writing tests against a database.

And if xUnit doesn't offer this out-of-the-box, maybe someone has a better pattern on how to solve this.

This question seems to go in a similar direction but I'm not necessarily fixed on a solution that has that structure.


回答1:


I learn the hard way that trying to share the entity framework database context over IClassFixture or CollectionFixtures would eventually end up in tests being polluted with another test data or deadlock/race conditions due to the parallel execution of xUnit, entity framework throwing exceptions because it already tracked that object with a given Id and more headaches like that. Personally, I would kindly recommend that for your specific use cause, stick the database context creation/cleanup within the constructor/dispose alternative such as:

    public class TestClass : IDisposable
    {
        DatabaseContext DatabaseContext;

        public TestClass()
        {
            var options = new DbContextOptionsBuilder<DatabaseContext>()
              .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
              .Options;

            DatabaseContext = new DatabaseContext(options);

            //insert the data that you want to be seeded for each test method:
            DatabaseContext.Set<Product>().Add(new Product() { Id = 1, Name = Guid.NewGuid().ToString() });
            DatabaseContext.SaveChanges();
        }

        [Fact]
        public void FirstTest()
        {
            var product = DatabaseContext.Set<Product>().FirstOrDefault(x => x.Id == 1).Name;
            //product evaluates to => 0f25a10b-1dfd-4b4b-a69d-4ec587fb465b
        }

        [Fact]
        public void SecondTest()
        {
            var product = DatabaseContext.Set<Product>().FirstOrDefault(x => x.Id == 1).Name;
            //product evaluates to => eb43d382-40a5-45d2-8da9-236d49b68c7a
            //It's different from firstTest because is another object
        }

        public void Dispose()
        {
            DatabaseContext.Dispose();
        }
    }

Of course you can always do some refinement, but the idea is there



来源:https://stackoverflow.com/questions/64800148/how-to-parametrize-a-xunit-class-fixture

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!