DBにデータを登録している時にエラーが発生したらロールバックを行いたいので、@Transactionalを使おうと思うのですが、
本当にロールバックが発生するか確認するためにJunitでこのテストを書きたいです。
以下のqiitaの記事にあるようなテスト対象のメソッド中にDBに登録しているメソッドを2つ呼び出している場合は、1つ目を正常に実行させて、2つ目が呼ばれた時にRuntime exceptionを発生させてロールバックを実現しています。
https://qiita.com/shimi58/items/60ea681c74188c4ea8bc
私が行いたいのは、以下のように100件ずつデータを登録するときのロールバックのテストです。
100件登録させて、101件以降のデータを登録中にロールバックを発生させて、テーブルの内容がテスト実行開始時の状態になっているかを確認したいです。
------------Service class--------------------------
@Slf4j @Service public class SampleService { @Autowired SampleLogic sampleLogic; @Transactional public CommandType execute() { try { //get items List<ItemEntity> itemEntities = sampleLogic.getItems(); //save item data sampleLogic.itemSave(itemEntities); } catch (Exception e) { log.error("Error Happened!!!", e); return CommandType.FAILURE; } return CommandType.SUCCESS; } }
-----logic class----------------------------------------
@Component public class SampleLogic { @Autowired SampleRepository sampleRepository; public List<ItemEntity> getItems() { List<ItemEntity> itemEntities = new ArrayList<>(); for(int i = 0; i < 1000; i++) { itemEntities.add(new ItemEntity(String.valueOf(i), "itemName")); } return itemEntities; } public void itemSave(List<ItemEntity> itemEntities) { Iterables.partition(itemEntities, 100).forEach(list -> { // save data per 100 sampleRepository.saveAll(itemEntities); }); } }
-----test class----------------------------------------
@ExtendWith(SpringExtension.class) @TestExecutionListeners({DirtiesContextTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionDbUnitTestExecutionListener.class}) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class SampleServiceTest { @InjectMocks private SampleService sampleService; @Test @DatabaseSetup("/itemPrep.xml") @ExpectedDatabase(value = "/testdata/CustomerServiceTest/init-data", assertionMode=DatabaseAssertionMode.NON_STRICT) void whenSaveMethodCalledRollBackHappen() { // // Assertions.assertEquals(CommandType.FAILURE, sampleService.execute()); } }
以下のようにメソッドの呼び出し回数によって異なる結果を返す方法でできるか試したのですが、List.classをモックするとitemSaveメソッドが実行されず、うまくいきませんでした。。もしどこか間違っていればご指摘お願いします。
https://reasonable-code.com/mockito-consecutive-calls/
@Test @DatabaseSetup("/itemPrep.xml") @ExpectedDatabase(value = "/testdata/CustomerServiceTest/init-data", assertionMode=DatabaseAssertionMode.NON_STRICT) void whenSaveMethodCalledRollBackHappen() { // List<ItemEntity> itemMockList = Mockito.mock(List.class); for(int i = 0; i < 100; i++) { Mockito.when(itemMockList.get(i)) .thenReturn(new ItemEntity(String.valueOf(i), "itemName")); } Mockito.when(itemMockList.get(101)).thenThrow(new RuntimeException()); //make sure execute method returns failure and item table is roll backed Assertions.assertEquals(CommandType.FAILURE, sampleService.execute()); }
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。