2011-01-17 17 views
6

Nel mio test di unità che autowired alcuni DataSources, che utilizzano gli URL comeJUnit + Derby + Primavera: calo db in memoria dopo ogni prova

jdbc:derby:memory:mydb;create=true 

per creare un DB in memoria.

Per eliminare un Derby in memoria db è necessario collegare con:

jdbc:derby:memory:mydb;drop=true 

Vorrei che questo accada dopo ogni prova e iniziare con un db fresca. Come posso farlo usando Spring?

risposta

4

How to shutdown Derby in-memory database Properly

mi ha dato un suggerimento per una soluzione:

mydb.drop.url = jdbc:derby:memory:mydb;drop=true 

    ... 

    <bean id="mydbDropUrl" class="java.lang.String"> 
    <constructor-arg value="${mydb.drop.url}" /> 
</bean> 

    ... 

    @Resource 
private String mydbDropUrl;   

    @After 
public void tearDown() { 
    try { 
     DriverManager.getConnection(mydbDropUrl); 
    } catch (SQLException e) { 
     // ignore 
    } 
} 

Un aspetto negativo è l'uso del costruttore String che accetta una stringa (un oggetto String immutabile intorno a un oggetto String immutabili). Ho letto che c'è un'annotazione @Value in Spring 3, che potrebbe essere d'aiuto, ma sto usando Spring 2.5.

Per favore fatemi sapere se avete una soluzione migliore.

+0

Seguendo http://docs.oracle.com/javadb/10.8.1.2/getstart/rwwdactivity3.html come esempio, piuttosto che prendere e scartare semplicemente 'SQLException' potrebbe essere meglio scartarlo solo se' e.getSQLState() .equals ("08006") ' – Raedwald

1

Se si utilizza la libreria diprimavera-test.jar, si può fare qualcosa di simile:

public class MyDataSourceSpringTest extends 
AbstractTransactionalDataSourceSpringContextTests { 

    @Override 
    protected String[] getConfigLocations() { 
     return new String[]{"classpath:test-context.xml"}; 
    } 

    @Override 
    protected void onSetUpInTransaction() throws Exception { 
     super.deleteFromTables(new String[]{"myTable"}); 
     super.executeSqlScript("file:db/load_data.sql", true); 
    } 
} 

E una versione aggiornata sulla base di ultimo commento, che scende db e ricrea le tabelle prima di ogni prova:

public class MyDataSourceSpringTest extends 
    AbstractTransactionalDataSourceSpringContextTests { 

     @Override 
     protected String[] getConfigLocations() { 
      return new String[]{"classpath:test-context.xml"}; 
     } 

     @Override 
     protected void onSetUpInTransaction() throws Exception { 
      super.executeSqlScript("file:db/recreate_tables.sql", true); 
     } 
} 
+0

yup, conosci le tue librerie (+1) –

+0

Non voglio eliminare i dati dalle tabelle o anche per rilasciare tabelle. Voglio eliminare l'intero db e ricrearlo per ogni test, che è più sicuro IMHO. – Puce

+0

È possibile creare uno script sql che rimuove il db e ricrea le tabelle ed eseguirlo come mostrato sopra. Aggiornerò la mia risposta in modo appropriato –

1

Basta fare qualcosa di simile:

public class DatabaseTest implements ApplicationContextAware { 
    private ApplicationContext context; 
    private DataSource source; 

    public void setApplicationContext(ApplicationContext applicationContext) { 
     this.context = applicationContext; 
    } 

    @Before 
    public void before() { 
     source = (DataSource) dataSource.getBean("dataSource", DataSource.class); 
    } 

    @After 
    public void after() { 
     source = null; 
    } 
} 

Fai in modo che il bean disponga di un prototipo (scope="prototype"). Ciò otterrà una nuova istanza della fonte di dati prima di ogni test.

+0

Questo è intelligente (+1), ma non molto pratico (significa che devi collegare manualmente tutti i bean che utilizzano l'origine dati) –

+0

Ho dei dubbi, se questo approccio funziona davvero: Stai dicendo che context.getBean() restituirà una nuova istanza piuttosto che la stessa istanza? Non penso che questo sia il caso, il che significa che non otterrai nulla. Esiste un'annotazione @DirtiesContext, ma anche quella non aprirebbe una connessione con "jdbc: derby: memory: mydb; drop = true" per eliminare il db in memoria. – Puce

2

Dopo la prova molla 3, è possibile utilizzare le annotazioni per iniettare configurazioni:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/spring-test.xml") 
public class MyTest { 
} 
5

C'è una via di database agnostico per fare questo se si utilizza Primavera insieme con Hibernate.

Assicurarsi che il contesto di applicazione verrà creato/distrutto prima/dopo ogni metodo di prova:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration({"classpath*:application-context-test.xml"}) 
@TestExecutionListeners({DirtiesContextTestExecutionListener.class, 
    DependencyInjectionTestExecutionListener.class}) 
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) 
public abstract class AbstractTest { 

} 

Istruire Hibernate per l'auto creare lo schema all'avvio e per eliminare lo schema allo spegnimento:

hibernate.hbm2ddl.auto = create-drop 

Ora, prima di ogni prova

  • il contesto dell'applicazione è creato e la richiedono d fagioli primaverili sono iniettati (primavera)
  • le strutture del database vengono create (ibernato)
  • l'importazione.SQL viene eseguita se presente (ibernazione)

e dopo ogni prova

  • il contesto dell'applicazione è distrutta (primavera)
  • lo schema di database viene eliminato (Hibernate).

Se si utilizzano le transazioni, è possibile aggiungere lo TransactionalTestExecutionListener.

0

Questo è ciò che facciamo all'inizio di ogni test.

  1. Eliminare tutti gli oggetti precedenti.

  2. Creare tutte le tabelle indicate nel create_table.sql

  3. valori Inserire sulle tabelle create in base a ciò che si desidera testare.

    @Before 
        public void initialInMemoryDatabase() throws IOException, FileNotFoundException { 
    
        inMemoryDerbyDatabase.dropAllObjects(); 
        inMemoryDerbyDatabase.executeSqlFile("/create_table_policy_version_manager.sql"); 
        inMemoryDerbyDatabase.executeSqlFile("/insert_table_policy_version_manager.sql"); 
    
        } 
    

funziona come un fascino!