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

huangapple go评论114阅读模式
英文:

xUnit Theory. How clear database between tests

问题

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

  1. public class TestDatabaseFixture
  2. {
  3. private const string ConnectionString = "DataSource=file::memory:?cache=shared";
  4. private static readonly object _lock = new();
  5. private static bool _databaseInitialized;
  6. public TestDatabaseFixture()
  7. {
  8. lock (_lock)
  9. {
  10. if (!_databaseInitialized)
  11. {
  12. using (var context = CreateContext())
  13. {
  14. context.Database.EnsureDeleted();
  15. context.Database.EnsureCreated();
  16. }
  17. _databaseInitialized = true;
  18. }
  19. }
  20. }
  21. public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false)
  22. {
  23. return new DbTrancheTest(
  24. new DbContextOptionsBuilder<DbTranche>()
  25. .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled)
  26. .UseSqlite(ConnectionString)
  27. .Options);
  28. }
  29. }

测试类

  1. public class TrancheServiceTest : IClassFixture<TestDatabaseFixture>
  2. {
  3. private TestDatabaseFixture Fixture { get; }
  4. public TrancheServiceTest(TestDatabaseFixture fixture)
  5. {
  6. Fixture = fixture;
  7. }
  8. [Theory]
  9. [InlineData(TrancheStatus.created, true)] // passed
  10. [InlineData(TrancheStatus.accepted, false)] // failed
  11. [InlineData(TrancheStatus.chanaged, true)] // failed
  12. [InlineData(TrancheStatus.waitforconf, false)] // failed
  13. [InlineData(TrancheStatus.rejected, false)] // failed
  14. public void Should_Set_Can_Edit_Flag_For_User(TrancheStatus status, bool result)
  15. {
  16. // Arrange
  17. using var context = Fixture.CreateContext();
  18. context.Database.EnsureDeleted();
  19. context.Database.EnsureCreated();
  20. var orderRepository = new TrancheOrderRepository(context);
  21. var userRepo = new UserRepository(context);
  22. var contrahentRepository = new ContrahentRepository(context);
  23. contrahentRepository.Add(new CONTRAHENT { ID = 1, NAME = "Contrahent1" });
  24. contrahentRepository.Save();
  25. var trancheOrder = new TRANCHE_ORDER
  26. {
  27. ID = 1,
  28. ISSUE_DATE = DateTime.Parse("2023-02-01"),
  29. LAST_UPDATE = DateTime.Parse("2023-02-01"),
  30. STATUS = (short)status,
  31. VOLUME = 0,
  32. USER = "",
  33. };
  34. orderRepository.Add(trancheOrder);
  35. orderRepository.Save();
  36. userRepo.Add(new USER { ID = 1, CAN_MODIFY = 1, DESCRIPTION = "Test user", FK_CONTRAHENT_ID = 1, NAME = "User1", USER_ID = 123 });
  37. userRepo.Save();
  38. var service = new TrancheService(contrahentRepository, orderRepository, userRepo);
  39. DateTime dateFrom = DateTime.Parse("2023-01-01");
  40. DateTime dateTo = DateTime.Parse("2023-12-01");
  41. // Act
  42. var trancheList = service.GetTrancheList(dateFrom, dateTo, 123, true);
  43. // Assert
  44. Assert.Collection(trancheList,
  45. e => Assert.Equal(result, e.CanEdit));
  46. }
  47. }

希望这对你有所帮助。

英文:

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.

  1. public class TestDatabaseFixture
  2. {
  3. private const string ConnectionString = &quot;DataSource=file::memory:?cache=shared&quot;;
  4. private static readonly object _lock = new();
  5. private static bool _databaseInitialized;
  6. public TestDatabaseFixture()
  7. {
  8. lock (_lock)
  9. {
  10. if (!_databaseInitialized)
  11. {
  12. using (var context = CreateContext())
  13. {
  14. context.Database.EnsureDeleted();
  15. context.Database.EnsureCreated();
  16. }
  17. _databaseInitialized = true;
  18. }
  19. }
  20. }
  21. public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false)
  22. =&gt; new DbTrancheTest(
  23. new DbContextOptionsBuilder&lt;DbTranche&gt;()
  24. .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled)
  25. .UseSqlite(ConnectionString)
  26. .Options);
  27. }

Test class

  1. public class TrancheServiceTest : IClassFixture&lt;TestDatabaseFixture&gt;
  2. {
  3. private TestDatabaseFixture Fixture { get; }
  4. // private readonly ITestOutputHelper output;
  5. public TrancheServiceTest(TestDatabaseFixture fixture)
  6. {
  7. Fixture = fixture;
  8. }
  9. [Theory]
  10. [InlineData(TrancheStatus.created, true)] // passed
  11. [InlineData(TrancheStatus.accepted, false)] // failed
  12. [InlineData(TrancheStatus.chanaged, true)] // failed
  13. [InlineData(TrancheStatus.waitforconf, false)] // failed
  14. [InlineData(TrancheStatus.rejected, false)] //failed
  15. public void Should_Set_Can_Edit_Flag_For_User(TrancheStatus status, bool result)
  16. {
  17. // Arrange
  18. using var context = Fixture.CreateContext();
  19. context.Database.EnsureDeleted();
  20. context.Database.EnsureCreated();
  21. var orderRepository = new TrancheOrderRepository(context);
  22. var userRepo = new UserRepository(context);
  23. var contrahentRepository = new ContrahentRepository(context);
  24. contrahentRepository.Add(new CONTRAHENT { ID = 1, NAME = &quot;Contrahent1&quot; });
  25. contrahentRepository.Save();
  26. var trancheOrder = new TRANCHE_ORDER
  27. {
  28. ID = 1,
  29. ISSUE_DATE = DateTime.Parse(&quot;2023-02-01&quot;),
  30. LAST_UPDATE = DateTime.Parse(&quot;2023-02-01&quot;),
  31. STATUS = (short)status,
  32. VOLUME = 0,
  33. USER = &quot;&quot;,
  34. };
  35. orderRepository.Add(trancheOrder);
  36. orderRepository.Save();
  37. userRepo.Add(new USER { ID = 1, CAN_MODIFY = 1, DESCRIPTION = &quot;Test user&quot;, FK_CONTRAHENT_ID = 1, NAME = &quot;User1&quot;, USER_ID = 123 });
  38. userRepo.Save();
  39. var service = new TrancheService(contrahentRepository, orderRepository, userRepo);
  40. DateTime dateFrom = DateTime.Parse(&quot;2023-01-01&quot;);
  41. DateTime dateTo = DateTime.Parse(&quot;2023-12-01&quot;);
  42. // Act
  43. var trancheList = service.GetTrancheList(dateFrom, dateTo, 123, true);
  44. // Assert
  45. Assert.Collection(trancheList,
  46. e =&gt; Assert.Equal(result, e.CanEdit));
  47. }
  48. }

答案1

得分: 1

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

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

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

  1. public TestDatabaseFixture()
  2. {
  3. lock (_lock)
  4. {
  5. using (var context = CreateContext())
  6. {
  7. context.Database.EnsureDeleted();
  8. context.Database.EnsureCreated();
  9. }
  10. }
  11. }
  12. public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false)
  13. => new DbTrancheTest(
  14. new DbContextOptionsBuilder<DbTranche>()
  15. .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled)
  16. .UseSqlite(string.Format(ConnectionString, DateTime.Now.Ticks))
  17. .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:

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

And update your code like this:

  1. public TestDatabaseFixture()
  2. {
  3. lock (_lock)
  4. {
  5. using (var context = CreateContext())
  6. {
  7. context.Database.EnsureDeleted();
  8. context.Database.EnsureCreated();
  9. }
  10. }
  11. }
  12. }
  13. public DbTrancheTest CreateContext(bool sensitiveDataLoggingEnabled = false)
  14. =&gt; new DbTrancheTest(
  15. new DbContextOptionsBuilder&lt;DbTranche&gt;()
  16. .EnableSensitiveDataLogging(sensitiveDataLoggingEnabled)
  17. .UseSqlite(string.Format(ConnectionString, DateTime.Now.Ticks))
  18. .Options);

答案2

得分: 0

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

  1. 使用 var context = new DbTrancheTest(
  2. new DbContextOptionsBuilder<DbTranche>()
  3. .EnableSensitiveDataLogging(false)
  4. .UseSqlite(string.Format("DataSource=file::memory:?{0}", Guid.NewGuid().ToString()))
  5. .Options);
  6. context.Database.EnsureDeleted();
  7. context.Database.EnsureCreated();
英文:

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

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

huangapple
  • 本文由 发表于 2023年8月10日 20:09:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875615.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定