问题描述:

I can't figure out how to make my integration tests rollback. If I insert, run tests, then query, I always get an empty table at the end.

  1. I insert with: INSERT INTO POKEMON_LOCATION VALUES (1, 2, 3);
  2. I run PokemonLocationDaoIT
  3. I query with SELECT * FROM POKEMON_LOCATION

Some code:

PokemonLocationDaoIT.java

package com.uprr.app.tng.spring.dao;

import com.uprr.app.tng.spring.config.DefaultDaoConfig;

import com.uprr.app.tng.spring.pojo.PokemonLocation;

import org.junit.Before;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.annotation.Rollback;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;

import javax.sql.DataSource;

import java.util.Collection;

import static org.assertj.core.api.Assertions.assertThat;

/**

* Created by david on 9/17/16.

*/

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes = DefaultDaoConfig.class)

@Transactional

@Rollback

public class PokemonLocationDaoIT {

private static final Operation DELETE_POKEMON_LOCATION = deleteAllFrom("POKEMON_LOCATION");

@Inject private PokemonLocationDao testable;

@Test

public void shouldBeEmpty() throws Exception {

this.testable.deleteAll();

final Collection<PokemonLocation> all = this.testable.getAll();

assertThat(all).isEmpty();

}

}

DefaultPokemonLocationDao

package com.uprr.app.tng.spring.dao;

import com.uprr.app.tng.spring.exception.InvalidPrimaryKeyException;

import com.uprr.app.tng.spring.pojo.PokemonLocation;

import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.RowMapper;

import javax.annotation.Nonnull;

import java.sql.SQLException;

import java.util.Collection;

/**

* Created by david on 9/17/16.

*/

public class DefaultPokemonLocationDao implements PokemonLocationDao {

@Nonnull private final JdbcTemplate jdbcTemplate;

@Nonnull private final RowCountMapper rowCountMapper;

@Nonnull private final RowMapper<PokemonLocation> rowMapper;

public DefaultPokemonLocationDao(@Nonnull final JdbcTemplate jdbcTemplate,

@Nonnull final RowCountMapper rowCountMapper,

@Nonnull final RowMapper<PokemonLocation> rowMapper) {

this.jdbcTemplate = jdbcTemplate;

this.rowCountMapper = rowCountMapper;

this.rowMapper = rowMapper;

}

@Override

public void create(@Nonnull final PokemonLocation object) {

final int id = 1; // FIXME: How to use PK generator

this.jdbcTemplate.update("INSERT INTO POKEMON_LOCATION VALUES (ID = :id, X = :x, Y = :y)", id, object.getX(),

object.getY());

}

@Override

public PokemonLocation get(@Nonnull final Integer id) {

return this.jdbcTemplate.queryForObject("SELECT * FROM POKEMON_LOCATION WHERE ID = :id", new Integer[]{id},

this.rowMapper);

}

@Override

public Collection<PokemonLocation> getAll() throws SQLException {

return this.jdbcTemplate.query("SELECT * FROM POKEMON_LOCATION", this.rowMapper);

}

@Override

public void update(@Nonnull final PokemonLocation location) {

final Integer primaryKey = location.getPrimaryKey();

if (null == primaryKey) {

throw new InvalidPrimaryKeyException("Can not update an object without a primary key. Try the save() " +

"method for creating new rows. " + location);

} else {

final String sql = "UPDATE POKEMON_LOCATION SET X = :x AND Y = :y WHERE ID = :id";

final int updatedRows = this.jdbcTemplate.update(sql, location.getX(), location.getY(), primaryKey);

if (1 != updatedRows) {

throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(sql, 1, updatedRows);

}

}

}

@Override

public void delete(@Nonnull final Integer id) {

final String sql = "DELETE FROM POKEMON_LOCATION WHERE ID = :id";

final int updatedRows = this.jdbcTemplate.update(sql, id);

if (1 != updatedRows) {

throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(sql, 1, updatedRows);

}

}

@Override

public void delete(@Nonnull final PokemonLocation object) {

final Integer pk = object.getPrimaryKey();

if (null == pk) {

throw new InvalidPrimaryKeyException("Cannot delete an object with a null primary key: " + object);

} else {

this.delete(pk);

}

}

@Override

public int deleteAll() {

return this.jdbcTemplate.update("DELETE FROM POKEMON_LOCATION");

}

@Override

public int count() {

return this.jdbcTemplate.queryForObject("SELECT count(*) FROM POKEMON_LOCATION", this.rowCountMapper);

}

}

DefaultDaoConfig.java

package com.uprr.app.tng.spring.config;

import com.uprr.app.tng.spring.dao.DefaultPokemonLocationDao;

import com.uprr.app.tng.spring.dao.PokemonLocationDao;

import com.uprr.app.tng.spring.dao.PokemonLocationMapper;

import com.uprr.app.tng.spring.dao.RowCountMapper;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Import;

import org.springframework.core.env.Environment;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import org.springframework.transaction.PlatformTransactionManager;

import org.springframework.transaction.annotation.EnableTransactionManagement;

import org.sqlite.SQLiteConfig;

import org.sqlite.SQLiteDataSource;

import javax.inject.Inject;

import javax.sql.DataSource;

/**

* Created by david on 9/17/16.

*/

@Import(PropertiesConfig.class)

@EnableTransactionManagement

public class DefaultDaoConfig implements DaoConfig {

@Inject private Environment environment;

@Bean

@Override

public PokemonLocationDao pokemonLocationDao() {

return new DefaultPokemonLocationDao(this.jdbcTemplate(), this.rowCountMapper(), this.pokemonLocationMapper());

}

@Bean

public PokemonLocationMapper pokemonLocationMapper() {

return new PokemonLocationMapper();

}

@Bean

public JdbcTemplate jdbcTemplate() {

return new JdbcTemplate(this.dataSource());

}

@Bean

public PlatformTransactionManager transactionManager() {

return new DataSourceTransactionManager(this.dataSource());

}

@Bean

public DataSource dataSource() {

final SQLiteDataSource dataSource = new SQLiteDataSource(new SQLiteConfig());

dataSource.setUrl(this.environment.getRequiredProperty("database.jdbc.url"));

return dataSource;

}

@Bean

public RowCountMapper rowCountMapper() {

return new RowCountMapper();

}

}

The log shows that Spring is rolling the transaction back:

Sep 25, 2016 5:24:15 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames

INFO: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]

Sep 25, 2016 5:24:15 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners

INFO: Using TestExecutionListeners: [or[email protected]64d2d351, org.springframework.test[email protected]1b68b9a4, org.springframewor[email protected]4f9a3314, org.springfra[email protected]3b2c72c2, org.springframew[email protected]491666ad, org.sp[email protected]176d53b2]

Sep 25, 2016 5:24:15 PM org.springframework.context.support.GenericApplicationContext prepareRefresh

INFO: Refreshing [email protected]c1ddd: startup date [Sun Sep 25 17:24:15 CDT 2016]; root of context hierarchy

Sep 25, 2016 5:24:15 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>

INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring

Sep 25, 2016 5:24:19 PM org.springframework.test.context.transaction.TransactionContext startTransaction

INFO: Began transaction (1) for test context [[email protected] testClass = PokemonLocationDaoIT, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = PokemonLocationDaoIT, locations = '{}', classes = '{class com.uprr.app.tng.spring.config.DefaultDaoConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [o[email protected]53142455]; rollback [true]

Sep 25, 2016 5:24:35 PM org.springframework.test.context.transaction.TransactionContext endTransaction

INFO: Rolled back transaction for test context [[email protected] testClass = PokemonLocationDaoIT, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = PokemonLocationDaoIT, locations = '{}', classes = '{class com.uprr.app.tng.spring.config.DefaultDaoConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].

So can anyone tell me why the rows are deleted after running this test?

Let me know if there is more code that you might need to see.

相关阅读:
Top