2010-11-22 5 views
2


J'essaie de tester ma couche DAO (qui est construite sur JPA) dans la séparation. Dans le test unitaire, j'utilise DbUnit pour remplir la base de données et Spring Test pour obtenir une instance de ApplicationContext.Problèmes d'utilisation de DbUnit avec Spring TestContext

Lorsque j'ai essayé d'utiliser SpringJunit4ClassRuner, le ApplicationContext a été injecté, mais la méthode getDataSet() de DbUnit n'a jamais été appelée.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = "/testdao.xml") 
public class SimpleJPATest extends DBTestCase implements ApplicationContextAware { 
    ... 

Alors j'ai essayé de supprimer l'annotation @RunWith, qui a supprimé les problèmes avec la méthode getDataSet(). Mais maintenant, je n'injecte plus l'instance ApplicationContext. J'ai essayé d'utiliser l'annotation @TestExecutionListeners, qui est supposée configurer le DependencyInjectionTestExecutionListener par défaut, mais l'AppContext n'est toujours pas injecté.

@TestExecutionListeners 
@ContextConfiguration(locations = "/testdao.xml") 
public class SimpleJPATest extends DBTestCase implements ApplicationContextAware { 
    ... 

Quelqu'un a-t-il des idées? Est-ce généralement une mauvaise idée de combiner ces deux cadres?


EDIT: voici le reste de la source pour la classe de test:

@TestExecutionListeners 
@ContextConfiguration(locations = "/testdao.xml") 
public class SimpleJPATest extends DBTestCase implements ApplicationContextAware { 

    static final String TEST_DB_PROPS_FILE = "testDb.properties"; 
    static final String DATASET_FILE = "testDataSet.xml"; 
    static Logger logger = Logger.getLogger(SimpleJPATest.class); 
    private ApplicationContext ctx; 

    public SimpleJPATest() throws Exception { 
     super(); 
     setDBUnitSystemProperties(loadDBProperties()); 
    } 

    @Test 
    public void testSimple() { 
     EntityManagerFactory emf = ctx.getBean("entityManagerFactory", EntityManagerFactory.class); 
     EntityManager em = emf.createEntityManager(); 
     GenericDAO<Club> clubDAO = new JpaGenericDAO<Club>(ClubEntity.class, "ClubEntity", em); 
     em.getTransaction().begin(); 
     Collection<Club> allClubs = clubDAO.findAll(); 
     em.getTransaction().commit(); 
     assertEquals(1, allClubs.size()); 
    } 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     this.ctx = applicationContext; 
    } 

    private void setDBUnitSystemProperties(Properties props) { 
     System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, 
       props.getProperty("db.driver")); 
     System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, 
       props.getProperty("db.url")); 
     System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, 
       props.getProperty("db.username")); 
     System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, 
       props.getProperty("db.password")); 

    } 

    private Properties loadDBProperties() throws Exception { 
     URL propsFile = ClassLoader.getSystemResource(TEST_DB_PROPS_FILE); 
     assert (propsFile != null); 
     Properties props = new Properties(); 
     props.load(propsFile.openStream()); 
     return props; 
    } 

    @Override 
    protected void setUpDatabaseConfig(DatabaseConfig config) { 
     config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, 
      new HsqldbDataTypeFactory()); 
    } 

    @Override 
    protected DatabaseOperation getSetUpOperation() throws Exception { 
     return DatabaseOperation.CLEAN_INSERT; 
    } 

    @Override 
    protected DatabaseOperation getTearDownOperation() throws Exception { 
     return DatabaseOperation.DELETE_ALL; 
    } 

    @Override 
    protected IDataSet getDataSet() throws Exception { 
     logger.debug("in getDataSet"); 
     URL dataSet = ClassLoader.getSystemResource(DATASET_FILE); 
     assert (dataSet != null); 
     FlatXmlDataSet result = new FlatXmlDataSetBuilder().build(dataSet); 
     return result; 
    } 
} 
+0

La raison pour laquelle aucune des méthodes DbTestCase n'est appelée est sans aucun doute le fait que la classe DbTestCase utilise l'API JUnit 3.8 et que j'essaie de m'exécuter avec SpringJUnit4ClassRunner. – prasopes

+0

J'ai réussi à utiliser DbUnit avec JUnit 4. Ce billet de blog m'a beaucoup aidé (regarder à travers la source de quelques classes clés de DbUnit n'a pas fait de mal non plus). http://ralf.schaeftlein.de/2009/01/05/dbunit-with-junit-4x-and-spring-for-testing-oracle-db-application/ – prasopes

Répondre

2

Je l'ai utilisé ces deux cadres ensemble sans aucun problème. J'ai dû faire des choses un peu différente de la norme mais pour l'obtenir au travail:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) 
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, 
     DirtiesContextTestExecutionListener.class }) 
public class MyDaoTest extends DBTestCase { 

@Autowired 
private MyDao myDao; 

/** 
* This is the underlying BasicDataSource used by Dao. If The Dao is using a 
* support class from Spring (i.e. HibernateDaoSupport) this is the 
* BasicDataSource that is used by Spring. 
*/ 
@Autowired 
private BasicDataSource dataSource; 

/** 
* DBUnit specific object to provide configuration to to properly state the 
* underlying database 
*/ 
private IDatabaseTester databaseTester; 

/** 
* Prepare the test instance by handling the Spring annotations and updating 
* the database to the stale state. 
* 
* @throws java.lang.Exception 
*/ 
@Before 
public void setUp() throws Exception { 
    databaseTester = new DataSourceDatabaseTester(dataSource); 
    databaseTester.setDataSet(this.getDataSet()); 
    databaseTester.setSetUpOperation(this.getSetUpOperation()); 
    databaseTester.onSetup(); 
} 

/** 
* Perform any required database clean up after the test runs to ensure the 
* stale state has not been dirtied for the next test. 
* 
* @throws java.lang.Exception 
*/ 
@After 
public void tearDown() throws Exception { 
    databaseTester.setTearDownOperation(this.getTearDownOperation()); 
    databaseTester.onTearDown(); 
} 

/** 
* Retrieve the DataSet to be used from Xml file. This Xml file should be 
* located on the classpath. 
*/ 
@Override 
protected IDataSet getDataSet() throws Exception { 
    final FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder(); 
    builder.setColumnSensing(true); 
    return builder.build(this.getClass().getClassLoader() 
      .getResourceAsStream("data.xml")); 
} 

/** 
* On setUp() refresh the database updating the data to the data in the 
* stale state. Cannot currently use CLEAN_INSERT due to foreign key 
* constraints. 
*/ 
@Override 
protected DatabaseOperation getSetUpOperation() { 
    return DatabaseOperation.CLEAN_INSERT; 
} 

/** 
* On tearDown() truncate the table bringing it back to the state it was in 
* before the tests started. 
*/ 
@Override 
protected DatabaseOperation getTearDownOperation() { 
    return DatabaseOperation.TRUNCATE_TABLE; 
} 

/** 
* Overridden to disable the closing of the connection for every test. 
*/ 
@Override 
protected void closeConnection(IDatabaseConnection conn) { 
    // Empty body on purpose. 
} 
// Continue TestClass here with test methods. 

J'ai dû faire des choses un peu plus manuel que je voudrais, mais le même scénario est applicable si vous essayez d'utiliser le runner JUnit Parameterized avec Spring (dans ce cas, vous devez démarrer le TextContext manuellement). La chose la plus importante à noter est que je substitue la méthode closeConnection() et la laisse vide. Cela remplace l'action par défaut consistant à fermer la connexion dataSource après chaque test, ce qui peut ajouter du temps inutile car la connexion devra être rouverte après chaque test.

Questions connexes