每次测试单元功能后如何重置数据库?

Posted

技术标签:

【中文标题】每次测试单元功能后如何重置数据库?【英文标题】:How to reset the database after each test unit function? 【发布时间】:2021-03-13 20:11:08 【问题描述】:

我有一个 junit5 的测试类。 我的生产程序使用 mysql 数据库。带有一些初始数据。 每次测试函数调用后如何重置我的数据库? 我应该使用弹簧吗?

这是我的测试类:

类 ATMTest

private ATM atm;

@BeforeEach
void setUp() 
    //TODO: initialize the atm here
    atm = new ATMClass();


@Test
void givenAccountNumberThatDoesNotExist_whenWithdraw_thenShouldThrowException() 
    Assertions.assertThrows(AccountNotFoundException.class,
            () -> atm.withdraw("14141414141", new BigDecimal("120.0")));



@Test
void givenValidAccountNumber_whenWithdrawAmountLargerThanTheAccountBalance_thenShouldThrowException() 
    Assertions.assertThrows(InsufficientFundsException.class,
            () -> atm.withdraw("123456789", new BigDecimal("20000.0")));


@Disabled
@Test
void whenWithdrawAmountLargerThanWhatInMachine_thenShouldThrowException() 
    atm.withdraw("123456789", new BigDecimal("1000.0"));
    atm.withdraw("111111111", new BigDecimal("1000.0"));

    Assertions.assertThrows(NotEnoughMoneyInATMException.class,
            () -> atm.withdraw("444444444", new BigDecimal("500.0")));



@Test
void whenWithdraw_thenSumOfReceivedBanknotesShouldEqualRequestedAmount() 
    BigDecimal requestedAmount = new BigDecimal(700);
    List<Banknote> receivedBanknotes = atm.withdraw("111111111", requestedAmount);

    BigDecimal sumOfAllBanknotes = receivedBanknotes.stream().map(Banknote::getValue).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

    Assertions.assertEquals(sumOfAllBanknotes.compareTo(requestedAmount), 0);



@Test
void givenAllFundsInAccountAreWithdrwan_whenWithdraw_shouldThrowException() 
    atm.withdraw("222222222", new BigDecimal("500"));
    atm.withdraw("222222222", new BigDecimal("500"));

    Assertions.assertThrows(InsufficientFundsException.class,
            () -> atm.withdraw("222222222", new BigDecimal("500")));

每个测试函数都需要使用数据的初始状态。

【问题讨论】:

为什么要使用实时数据库进行单元测试? 使用装有数据库的容器。 您可以使用像 h2 这样的内存数据库,或者使用带有 AfterEach 或 After 注释的 tearDown() 在其中您将添加逻辑以恢复测试运行期间发生的任何插入/更新等。 您可能想了解 schema migration 工具,例如 Flyway、Liquibase 等。 您可以每次设置初始数据以确保一致性。 【参考方案1】:

单元测试的目标是隔离程序的每个部分并显示各个部分是正确的。 因此,您只需提供一些 mocksstubs(例如 Mockito)来模拟从数据库返回的值,而不是使用实时数据库。

否则你所做的就是集成测试。

回答问题,使用@BeforeEach 创建基本类。在那里您可以实现截断所有表。这样,在每个@Test 方法之前,您都可以设置您需要的所有数据。

【讨论】:

【参考方案2】:

如果您想进行集成测试(而不是单元测试),希望将数据库重置为已知状态,我建议您使用第三方库,例如 DbUnit。 (http://dbunit.sourceforge.net)

如果项目很小并且“设置”并不难,您也可以自己动手。

【讨论】:

以上是关于每次测试单元功能后如何重置数据库?的主要内容,如果未能解决你的问题,请参考以下文章

Spring H2 Test DB 在每次测试之前不会重置

如何在单元测试中使用 Flyway 时重置 SQLite 自动增量

如何在每次测试之前重置或清除 ApolloProvider 的 useQuery 模拟?

为啥每次单元测试后我的数据库都没有被清除?

java怎么做单元测试,紧急!

使用 Testcontainers 和 Liquibase 时在测试之间重置数据库