1

In spring boot I'm trying to create my first transactional test, but the trasaction doesn't work.

@TestPropertySource(locations = "classpath:test.properties")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringJUnit4ClassRunner.class)
//@RunWith(SpringRunner.class)
@Transactional
@TestExecutionListeners(
    mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
    listeners = {TransactionalTestExecutionListener.class}
)
public class IntegrationTests
{
    @Autowired
    TemperatureLogRepository temperatureLogRepository;

    @Test
    @SqlGroup({
        @Sql(
            executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
            config = @SqlConfig(transactionMode = ISOLATED),
            scripts = "classpath:sqls/insertRecords2.sql"
        )
    })
    public void firstRepoTest() throws SQLException
    {
        assertThat(temperatureLogRepository.getFullList().size()).isEqualByComparingTo(0);
    }
}

I know that SqlGroup is not necessary, but there will be more files added.

That I have now:

  1. SQL file executed well and inserted to the DB.
  2. The getFullList() method can read it and returns with the right data.
  3. After the test I still have the data in the DB, there is no rollback on the transaction.

I'm not exactly sure they are running in the same transaction. Is it possible to be the data commited to the db before the getFullList() method run?

What I need:

  1. @Sql inserts data to the transaction.
  2. getFullList() read the data from the transaction.
  3. Test the returned data.
  4. Rollback the transaction.
Arvind Katte
  • 995
  • 2
  • 10
  • 20
Krizsán Balazs
  • 386
  • 1
  • 4
  • 18

1 Answers1

2

From Spring Testing - Executing SQL scripts declaratively with @Sql:

Script execution phases

By default, SQL scripts will be executed before the corresponding test method. However, if a particular set of scripts needs to be executed after the test method — for example, to clean up database state — the executionPhase attribute in @Sql can be used as seen in the following example. Note that ISOLATED and AFTER_TEST_METHOD are statically imported from Sql.TransactionMode and Sql.ExecutionPhase respectively.

@Test 
@Sql(
    scripts = "create-test-data.sql",
    config = @SqlConfig(transactionMode = ISOLATED) ) @Sql(
    scripts = "delete-test-data.sql",
    config = @SqlConfig(transactionMode = ISOLATED),
    executionPhase = AFTER_TEST_METHOD ) 
public void userTest {
    // execute code that needs the test data to be committed
    // to the database outside of the test's transaction 
}

Related question: How to execute @Sql before a @Before method

UPDATE

Remove @SqlConfig from @Sql:

config = @SqlConfig(transactionMode = ISOLATED)

Or change to:

config = @SqlConfig(transactionMode = TransactionMode.INFERRED)

SQL script runs in separate transaction which is not roll backed:

org.springframework.test.context.jdbc.SqlConfig.TransactionMode.ISOLATED

Indicates that SQL scripts should always be executed in a new, isolated transaction that will be immediately committed.

Justinas Jakavonis
  • 8,220
  • 10
  • 69
  • 114
  • I'm using the befre phase. The query runs fine. But I don't wanna run anything after the test, I need a simple rollback. I don't want to commit anythin the DB. And my problem is the rollback, it looks like I have a transaction commit. – Krizsán Balazs Dec 27 '17 at 12:03
  • Updated the answer. – Justinas Jakavonis Dec 27 '17 at 12:44
  • I already tried it. In this case I don't see anything in the test DB after the test, so rollback fine, but my repo can't read the transaction. Any other idea? :) – Krizsán Balazs Dec 27 '17 at 16:25
  • Do you get any exception? I have tried with similar config and it worked. – Justinas Jakavonis Dec 27 '17 at 16:33
  • Maybe do you use more than 1 data source / DB config? – Justinas Jakavonis Dec 27 '17 at 16:35
  • Nope, my select in the repo runs on an empty table. So my repo is running in a different transaction. They should be set for the same transaction. – Krizsán Balazs Dec 27 '17 at 16:37
  • I use this `DriverManager.getConnection(env.getProperty("psql.connection"));` for my repo and I have a `test.properties with the spring.datasource.*` for the test db setup. Should I somehow inject the connection from the test to the repo? – Krizsán Balazs Dec 27 '17 at 16:42
  • Why do you need @TestExecutionListeners? Try remove. – Justinas Jakavonis Dec 27 '17 at 17:07
  • I don't really know what I need, I'm just trying. :) I removed but it is the same problem. Now I'm trying to mock my ConnectionService to be able return with the same DataSource as the test. I think if I can do that, my repo will be able read the same transaction. – Krizsán Balazs Dec 28 '17 at 15:36
  • I have used these annotations for test class: /@RunWith(SpringRunner.class) /@SpringBootTest (properties = {...}) /@Transactional – Justinas Jakavonis Dec 28 '17 at 15:48
  • Don't you have a public repo with example? If I print out the connection in the repo it is: `org.postgresql.jdbc.PgConnection@67acfde9` but in the test: `ProxyConnection[PooledConnection[org.postgresql.jdbc.PgConnection@7548e1fb]]`. This different resource id can be the problem of the transaction. Is it possible to mock a bean, that I don't use directly in the test, it is only autowired in the abstract repo? – Krizsán Balazs Dec 28 '17 at 20:25
  • I have a ConnectionService returning with an: `DriverManager.getConnection(env.getProperty("psql.connection"));` I use this object in the repo. Could it be a problem if I made it manally? Or should it be created by the fw? – Krizsán Balazs Dec 29 '17 at 02:54
  • Check the second answer: https://stackoverflow.com/questions/12626502/rollback-transaction-after-test – Justinas Jakavonis Dec 29 '17 at 10:04
  • It looks like I can't solve this problem for now. Maybe once later if I have more experience I try it once more. Or if I can sit down with a spring developer directly for a half hour. For now I will clean the db with simple tear down sql. Thanks anyway for your lot of comments! – Krizsán Balazs Dec 29 '17 at 13:47