I need to test rollback scenario for this service:
@Service
public class MyService2 {
private final Entity2Repo entity2Repo;
public MyService2(Entity2Repo entity2Repo) {
this.entity2Repo = entity2Repo;
}
public void create(Long entity1Id) {
Entity2 entity2 = new Entity2();
entity2.assignToEntity1(entity1Id);
entity2Repo.save(entity2);
}
}
I've created this Integration test case:
@Transactional
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JpaApplication.class)
public class MyServiceIntTest {
@Autowired
private Entity1Repo entity1Repo;
@Autowired
private EntityManager entityManager;
@Test
public void create() throws Exception {
MyService2 mock = mock(MyService2.class);
doThrow(new RuntimeException("bla bla")).when(mock).create(anyLong());
MyService myService = new MyService(entity1Repo, mock);
try {
myService.create("some name");
fail("should never fails");
} catch (RuntimeException e) {
assertThat(e.getMessage()).isEqualTo("bla bla"); // success
}
Entity1 dbEntity1 = (Entity1) entityManager.createQuery("from Entity1 where name = 'some name'").getSingleResult();
assertThat(dbEntity1).isNull(); // fail, however it should be null as it is rolled-back
}
}
The question is, why the organization object is still saved in the Database after the rollback happens?
EDIT: Complete source code at github: https://github.com/mhewedy-playground/test-transaction-rollback
The problem was, I was creating the MyService
object out of spring context and then expecting the transaction manager to start.
I've changed the test code to the following and now it works successfully:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JpaApplication.class)
public class MyServiceIntTest {
@Autowired
private EntityManager entityManager;
@Autowired
private MyService myService;
@MockBean
private MyService2 myService2;
@Transactional
@Test(expected = RuntimeException.class)
public void createWillRollback() throws Exception {
doThrow(new RuntimeException("bla bla")).when(myService2).create(anyLong());
myService.create("some name");
assertThat(count()).isEqualTo(0);
}
@Transactional
@Test
public void create() throws Exception {
doNothing().when(myService2).create(anyLong());
myService.create("some name");
assertThat(count()).isEqualTo(1);
}
private long count() {
return ((Long) entityManager.createQuery("select count(*) from Entity1").getSingleResult());
}
}