1

I've done some research through the q&a around here regarding the issue. many questions seem to address it, but not really.

So here's the thing:

  • I got a CaseController, which delegates to CaseService, which delegate in turn to CaseRepository.

  • I got @Transactional on top of each method on CaseServiceImpl

  • I got a CaseControllerIntegrationTest, from which I perform RESTful requests to my CaseController and test full cycles.

Problem is - my transactions are not rolled back.

One of the tests is

@Test 
public void verifyDeleteSuccessfulOnExistingCase() {

        final String urlWithPlaceholders = serverPrefix + RequestMappings.CASES_RESOURCE_MAPPING + "/{caseId}";

        final ResponseEntity<CaseResource> response =
                restTemplate.exchange(
                        urlWithPlaceholders,
                        HttpMethod.DELETE,
                        null,
                        CaseResource.class, existingWsId_1, caseId);

        assertThat(response, notNullValue());
        assertThat(response.getBody(), nullValue());
        assertThat(response.getStatusCode(), is(HttpStatus.NO_CONTENT));
        assertThat(caseRepository.exists(caseId), is(false));

}

In this test I delete a case which I had inserted for me in startup thanks to hibernate and import.sql

Test is successful, problem is that I want to keep on addressing this case in the next tests, but the transaction seems not be rolled back, and the case is permanently deleted and not available for the next tests.

  • I have tried moving @Transactional from CaseServiceImpl to the CaseController, yet it didn't make a difference.

  • I can say that my lower lever CaseRepositoryTest successfully performs the rollback after each test.

On top of CaseControllerIntegrationTest I got:

@ActiveProfiles("integration-test")
@Transactional
@TransactionConfiguration
@IntegrationTest
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = AppConfiguration.class)
public class CaseControllerIntegrationTest {
...

AppConfiguration looks like this:

@Configuration
@EnableAutoConfiguration
@ComponentScan
@EnableTransactionManagement
public class AppConfiguration {
}

The db I'm using is hsqldb

Last important piece of info - The log actually indicates that the rollback was done:

2014-05-15 07:54:44.391 TRACE - o.s.t.c.t.TransactionalTestExecutionListener - Ending transaction for test context [DefaultTestContext@2eb0cefe testClass = CaseControllerIntegrationTest, testInstance = om.services.casemanagement.web.CaseControllerIntegrationTest@5a2ae1ab, testMethod = verifyDeleteSuccessfulOnExistingCase@CaseControllerIntegrationTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@2bec068b testClass = CaseControllerIntegrationTest, locations = '{}', classes = '{class om.services.AppConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{integration-test}', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]]; transaction status [org.springframework.transaction.support.DefaultTransactionStatus@3869a6e5]; rollback [true]

2014-05-15 07:54:44.403 INFO - o.s.t.c.t.TransactionalTestExecutionListener - Rolled back transaction after test execution for test context [DefaultTestContext@2eb0cefe testClass = CaseControllerIntegrationTest, testInstance = om.services.casemanagement.web.CaseControllerIntegrationTest@5a2ae1ab, testMethod = verifyDeleteSuccessfulOnExistingCase@CaseControllerIntegrationTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@2bec068b testClass = CaseControllerIntegrationTest, locations = '{}', classes = '{class om.services.AppConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{integration-test}', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]]

I'm using Spring 4.0.3 distribution.

Any ideas?

user3509688
  • 11
  • 1
  • 2

3 Answers3

3

See what you do here:

You send an http request from thread1, which is caught and handled by a web container's thread2. The former has no control of the transactions managed at the latter.

Should you hold a CaseController instance and make explicit calls on its methods directly from the test method, you'll enjoy the auto-rollback functionality given to you by @Transactional.

kumetix
  • 1,032
  • 1
  • 12
  • 18
3

Although @kumetix alluded to it, the correct answer to this is that, there is no way of rolling back the transactions triggered by the requests made through the RestTemplate in a test method

Your only option is to rollback the transactions through a manual delete.

Refer this link with similiar question for another opinion.

Hope that helps.

HopeKing
  • 3,317
  • 7
  • 39
  • 62
0

This way works for me.

Step 1: Create a private CaseService and add @Autowired on it. Also add a private MockMvc variable.

private MockMvc restCaseController;

@Autowired
private CaseService caseService; 

Step 2: Create a setup method and annotate it with @Before.

@Before
private void setup() {
  MockitoAnnotations.initMocks(this);
  CaseController casecontroller = new CaseController(caseService);
  this.restCaseController = 
  MockMvcBuilders.standaloneSetup(casecontroller).build();
}

Step 3: Create test method, annotate it with @Test and @Transactional.

@Test
@Transactional
public void testMethod() {
    restCaseController.perform(post("/api/post")
                      .contentType(MediaType.APPLICATION_JSON_UTF8)
                      .content(jsonObject))
                      .andExpect(status().isCreated());
}

This way works for me and I am able to get response without any rollback issue.

dev
  • 451
  • 4
  • 10
  • 23