51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

xUnit理论。如何在测试之间清除数据库。

英文:

xUnit Theory. How clear database between tests

问题 {#heading}

我使用 xUnit [Theory] 编写测试。我的问题是,我运行第一个测试它通过了,而第二个测试抛出异常 ---- Microsoft.Data.Sqlite.SqliteException:SQLite 错误 19:'UNIQUE constraint failed: CONTRAHENT.ID'。当我分别运行每个测试时,在测试资源管理器中它们都通过了。因此,我认为在第二次运行之前数据库没有被清除/释放。

public class TestDatabaseFixture
{
    private const string ConnectionString = "DataSource=file::memory:?cache=shared";
    private static readonly object _lock = new();
    private static bool _databaseInitialized;
public TestDatabaseFixture()
{
    lock (_lock)
    {
        if (!_databaseInitialized)
        {
            using (var context = CreateContext())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();
            }
        _databaseInitialized = true;
    }
}

}

public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false) { return new DbTrancheTest( new DbContextOptionsBuilder<DbTranche>() .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled) .UseSqlite(ConnectionString) .Options); }

}

测试类

public class TrancheServiceTest : IClassFixture<TestDatabaseFixture>
{
    private TestDatabaseFixture Fixture { get; }
public TrancheServiceTest(TestDatabaseFixture fixture)
{
    Fixture = fixture;
}

[Theory] [InlineData(TrancheStatus.created, true)] // passed [InlineData(TrancheStatus.accepted, false)] // failed [InlineData(TrancheStatus.chanaged, true)] // failed [InlineData(TrancheStatus.waitforconf, false)] // failed [InlineData(TrancheStatus.rejected, false)] // failed public void Should_Set_Can_Edit_Flag_For_User(TrancheStatus status, bool result) { // Arrange using var context = Fixture.CreateContext(); context.Database.EnsureDeleted(); context.Database.EnsureCreated();

var orderRepository = new TrancheOrderRepository(context);
var userRepo = new UserRepository(context);
var contrahentRepository = new ContrahentRepository(context);

contrahentRepository.Add(new CONTRAHENT { ID = 1, NAME = &amp;quot;Contrahent1&amp;quot; }); contrahentRepository.Save();

var trancheOrder = new TRANCHE_ORDER { ID = 1, ISSUE_DATE = DateTime.Parse(&amp;quot;2023-02-01&amp;quot;), LAST_UPDATE = DateTime.Parse(&amp;quot;2023-02-01&amp;quot;), STATUS = (short)status, VOLUME = 0, USER = &amp;quot;&amp;quot;, }; orderRepository.Add(trancheOrder); orderRepository.Save();

userRepo.Add(new USER { ID = 1, CAN_MODIFY = 1, DESCRIPTION = &amp;quot;Test user&amp;quot;, FK_CONTRAHENT_ID = 1, NAME = &amp;quot;User1&amp;quot;, USER_ID = 123 }); userRepo.Save();

var service = new TrancheService(contrahentRepository, orderRepository, userRepo); DateTime dateFrom = DateTime.Parse(&amp;quot;2023-01-01&amp;quot;); DateTime dateTo = DateTime.Parse(&amp;quot;2023-12-01&amp;quot;);

// Act var trancheList = service.GetTrancheList(dateFrom, dateTo, 123, true);

// Assert Assert.Collection(trancheList, e =&amp;gt; Assert.Equal(result, e.CanEdit));

}

}

希望这对你有所帮助。 英文:

I write test using xUnit [Theory]. My problem is that I run first test and it pass, while 2nd test throw exception ---- Microsoft.Data.Sqlite.SqliteException : SQLite Error 19: 'UNIQUE constraint failed: CONTRAHENT.ID'. When I run each test separately, in Test Explorer they all passed. So I assume that database is not cleared/disposed before second run.

 public class TestDatabaseFixture
    {
        private const string ConnectionString = &quot;DataSource=file::memory:?cache=shared&quot;;
        private static readonly object _lock = new();
        private static bool _databaseInitialized;
    public TestDatabaseFixture()
    {
    lock (_lock)
    {
        if (!_databaseInitialized)
        {
            using (var context = CreateContext())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();
            }
        _databaseInitialized = true;
    }
}

}

public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false) =&amp;amp;amp;gt; new DbTrancheTest( new DbContextOptionsBuilder&amp;amp;amp;lt;DbTranche&amp;amp;amp;gt;() .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled) .UseSqlite(ConnectionString) .Options);

}


Test class

public class TrancheServiceTest : IClassFixture&lt;TestDatabaseFixture&gt;
    {
        private TestDatabaseFixture Fixture { get; }
        // private readonly ITestOutputHelper output;
        public TrancheServiceTest(TestDatabaseFixture fixture)
        {
            Fixture = fixture;
        }
        [Theory]
        [InlineData(TrancheStatus.created, true)] // passed
        [InlineData(TrancheStatus.accepted, false)] // failed
        [InlineData(TrancheStatus.chanaged, true)] // failed
        [InlineData(TrancheStatus.waitforconf, false)] // failed
        [InlineData(TrancheStatus.rejected, false)] //failed
    public void Should_Set_Can_Edit_Flag_For_User(TrancheStatus status, bool result)
    {
        // Arrange
        using var context = Fixture.CreateContext();
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();
    var orderRepository = new TrancheOrderRepository(context);
    var userRepo = new UserRepository(context);
    var contrahentRepository = new ContrahentRepository(context);

    contrahentRepository.Add(new CONTRAHENT { ID = 1, NAME = &amp;amp;amp;amp;quot;Contrahent1&amp;amp;amp;amp;quot; });
    contrahentRepository.Save();

    var trancheOrder = new TRANCHE_ORDER
    {
        ID = 1,
        ISSUE_DATE = DateTime.Parse(&amp;amp;amp;amp;quot;2023-02-01&amp;amp;amp;amp;quot;),
        LAST_UPDATE = DateTime.Parse(&amp;amp;amp;amp;quot;2023-02-01&amp;amp;amp;amp;quot;),
        STATUS = (short)status,
        VOLUME = 0,
        USER = &amp;amp;amp;amp;quot;&amp;amp;amp;amp;quot;,
    };
    orderRepository.Add(trancheOrder);
    orderRepository.Save();

    userRepo.Add(new USER { ID = 1, CAN_MODIFY = 1, DESCRIPTION = &amp;amp;amp;amp;quot;Test user&amp;amp;amp;amp;quot;, FK_CONTRAHENT_ID = 1, NAME = &amp;amp;amp;amp;quot;User1&amp;amp;amp;amp;quot;, USER_ID = 123 });
    userRepo.Save();

    var service = new TrancheService(contrahentRepository, orderRepository, userRepo);
    DateTime dateFrom = DateTime.Parse(&amp;amp;amp;amp;quot;2023-01-01&amp;amp;amp;amp;quot;);
    DateTime dateTo = DateTime.Parse(&amp;amp;amp;amp;quot;2023-12-01&amp;amp;amp;amp;quot;);

    // Act
    var trancheList = service.GetTrancheList(dateFrom, dateTo, 123, true);

    // Assert
    Assert.Collection(trancheList,
        e =&amp;amp;amp;amp;gt; Assert.Equal(result, e.CanEdit));

}

}


答案1 {#1}

得分: 1

就像 @fildor 所说的那样,您可以每次创建一个新的数据库。为此,您可以使用一个类似这样的 连接字符串

ConnectionString = "file:{0}?mode=memory";  

然后按照以下方式更新您的代码:

public TestDatabaseFixture()
{
    lock (_lock)
    {
        using (var context = CreateContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();
        }
    }
}

public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false) => new DbTrancheTest( new DbContextOptionsBuilder<DbTranche>() .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled) .UseSqlite(string.Format(ConnectionString, DateTime.Now.Ticks)) .Options);

英文:

Just like @fildor said, you can create a new DB each time. For that, you can use a connection string which looks like this:

ConnectionString = &quot;file:{0}?mode=memory&quot;;  

And update your code like this:

public TestDatabaseFixture()
    {
    lock (_lock)
    {
            using (var context = CreateContext())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();
            }
        }
    }
}

public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false) =&amp;gt; new DbTrancheTest( new DbContextOptionsBuilder&amp;lt;DbTranche&amp;gt;() .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled) .UseSqlite(string.Format(ConnectionString, DateTime.Now.Ticks)) .Options);


答案2 {#2}

得分: 0

我最终在每个单独的测试中创建了上下文,就像这样。所有的测试都通过了。

使用 var context = new DbTrancheTest(
    new DbContextOptionsBuilder<DbTranche>()
    .EnableSensitiveDataLogging(false)
    .UseSqlite(string.Format("DataSource=file::memory:?{0}", Guid.NewGuid().ToString()))
    .Options);
`context.Database.EnsureDeleted();
context.Database.EnsureCreated();
`

英文:

I end up creating context in each individual test like this. All tests passed.

  using var context = new DbTrancheTest(
        new DbContextOptionsBuilder&lt;DbTranche&gt;()
        .EnableSensitiveDataLogging(false)
        .UseSqlite(string.Format(&quot;DataSource=file::memory:?{0}&quot;, Guid.NewGuid().ToString()))
        .Options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();



赞(6)
未经允许不得转载:工具盒子 » xUnit理论。如何在测试之间清除数据库。