Domanda

stiamo usando Primavera per i miei scopi applicativi, e framework Spring test per i test unitari. Abbiamo un piccolo problema però: il codice dell'applicazione carica un contesto di applicazione della molla da un elenco di luoghi (file XML) nel classpath. Ma quando si corre il nostro test di unità, vogliamo che alcuni dei fagioli di primavera che si prende in giro, invece di classi a tutti gli effetti di implementazione. Inoltre, per alcuni test di unità che vogliamo alcuni chicchi di diventare prende in giro, mentre per gli altri test di unità che vogliamo altri fagioli diventino prende in giro, come stiamo testando diversi strati della applicazione.

Tutto ciò significa che voglio ridefinire i fagioli specifico contesto di applicazione e aggiornare il contesto quando lo si desidera. Nel fare questo, voglio ridefinire solo una piccola parte dei fagioli situati in uno (o più) file di definizione originale fagioli XML. Non riesco a trovare un modo semplice per farlo. E 'sempre considerato che la primavera è un'unità Testing Framework amichevole quindi devo essere perso qualcosa qui.

Avete delle idee su come farlo?

Grazie.

È stato utile?

Soluzione

Vorrei proporre un TestClass personalizzato e alcune regole semplici per le posizioni dei bean.xml primavera

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath*:spring/*.xml",
    "classpath*:spring/persistence/*.xml",
    "classpath*:spring/mock/*.xml"})
@Transactional
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class})
public abstract class AbstractHibernateTests implements ApplicationContextAware 
{

    /**
     * Logger for Subclasses.
     */
    protected final Logger LOG = LoggerFactory.getLogger(getClass());

    /**
     * The {@link ApplicationContext} that was injected into this test instance
     * via {@link #setApplicationContext(ApplicationContext)}.
     */
    protected ApplicationContext applicationContext;

    /**
     * Set the {@link ApplicationContext} to be used by this test instance,
     * provided via {@link ApplicationContextAware} semantics.
     */
    @Override
    public final void setApplicationContext(
            final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

se ci sono mock-bean.xml nella posizione specificata, si sostituiscono tutte bean.xml "reale" nei luoghi "normali" - le posizioni normali potrebbero differire

ma ... non avrei mai mescolare i fagioli finte e non finte è difficile rintracciare i problemi, quando l'applicazione cresce.

Altri suggerimenti

Una delle ragioni per la primavera è descritto come test-amichevole è perché può essere facile da solo nuovo o roba finta nel test di unità.

In alternativa abbiamo usato la seguente configurazione con grande successo, e penso che è abbastanza vicino a quello che si vuole, vorrei con forza consiglio:

Per tutti i fagioli che necessitano di diverse implementazioni in contesti diversi, passare al cablaggio a base di annotazione. È possibile lasciare gli altri così come sono.

Implementare la seguente serie di annotazioni

 <context:component-scan base-package="com.foobar">
     <context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>
     <context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
 </context:component-scan>

Poi di annotare le Live implementazioni con @Repository, i tuoi stub implementazioni con @StubRepository, qualsiasi codice che dovrebbe essere presente nel dispositivo di unità di prova solo con @TestScopedComponent . Si può incorrere in che necessitano di un altro paio di annotazioni, ma questi sono un grande inizio.

Se avete un sacco di spring.xml, si avrà probabilmente bisogno di fare un paio di nuovi file XML di primavera che, in fondo contengono solo le definizioni di componente-scan. Che normalmente basta aggiungere questi file al tuo elenco @ContextConfiguration regolare. La ragione di questo è perché si finisce spesso con diverse configurazioni del contesto-scan (credetemi, fare almeno 1 più annotazioni se si sta facendo web-test, che rende per 4 combinazioni pertinenti)

Quindi è fondamentalmente utilizzare il

@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)

Si noti che questa configurazione non ti permettono di avere alternati combinazioni di dati stub / live. Abbiamo provato questo, e penso che ha provocato un disastro io non lo consiglio a nessuno;) O si locanda filo il set completo di stub o il set completo di servizi in tempo reale

.

Usiamo principalmente dipendenze stub auto-wired durante il test gui vicino roba in cui le dipendenze sono di solito abbastanza sostanziale. Nelle zone più pulite del codice che utilizziamo più regolare unit test.

Nel nostro sistema abbiamo i seguenti file XML per il componente-scan:

  • per la produzione di web regolare
  • per iniziare web con mozziconi solo
  • per test di integrazione (in JUnit)
  • per i test unitari (in junit)
  • per le prove di web selenio (in JUnit)

Questo significa che completamente abbiamo 5 differenti configurazioni a livello di sistema che possiamo iniziare l'applicazione con. Dal momento che usiamo solo le annotazioni, la primavera è abbastanza veloce per autowire anche quelle unit test che vogliamo cablata. So che questo è non tradizionale, ma è davvero grande.

In test di integrazione eseguiti con piena messa a punto dal vivo, e una o due volte ho deciso di ottenere davvero pragmatica e vogliono avere un 5 cablaggi live e un singolo finto:

public class HybridTest {
   @Autowired
   MyTestSubject myTestSubject;


   @Test
   public void testWith5LiveServicesAndOneMock(){
     MyServiceLive service = myTestSubject.getMyService();
     try {
          MyService mock = EasyMock.create(...)
          myTestSubject.setMyService( mock);

           .. do funky test  with lots of live but one mock object

     } finally {
          myTestSubject.setMyService( service);
     }


   }
}

So che i puristi di prova saranno tutti su di me per questo. Ma a volte è solo una soluzione molto pragmatica che risulta essere molto elegante quando l'alternativa sarebbe davvero brutto. Anche in questo caso è di solito in quelle aree gui-vicino.

con @InjectedMock annotazione

E mi ha salvato un sacco di tempo. Basta usare

@Mock
SomeClass mockedSomeClass

@InjectMock
ClassUsingSomeClass service

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

e tutti i vostri problemi sono risolti. Mockito sostituirà l'iniezione molla di dipendenza con un finto. Ho appena usato io stesso e funziona benissimo.

Ci sono alcune soluzioni molto complesse e potenti elencati qui.

Ma c'è un molto, molto più semplice modo per realizzare ciò che Stas ha chiesto, che non comporta la modifica qualcosa di diverso da una riga di codice nel metodo di prova. Funziona per i test unitari e test di integrazione Primavera allo stesso modo, per le dipendenze autowired, private e campi protetti.

Qui è:

junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);

Si può anche scrivere il test di unità per non richiedere alcun lookup affatto:

@ContextConfiguration(locations = { "classpath:/path/to/test-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyBeanTest {

    @Autowired
    private MyBean myBean; // the component under test

    @Test
    public void testMyBean() {
        ...
    }
}

Questo dà un modo semplice per combinare i file di configurazione reali con i file di configurazione di prova.

Ad esempio, quando si usa hibernate, potrei avere il mio fagiolo sessionFactory in un unico file di configurazione (per essere utilizzato in entrambi i test e l'applicazione principale), e hanno da dataSource fagiolo in un altro file di configurazione (si potrebbe usare un DriverManagerDataSource per un db in memoria, l'altro potrebbe utilizzare un JNDI-lookup).

Ma, sicuramente tener conto di prendere @ Cletus di avvertimento; -)

Facile. Si utilizza un contesto di un'applicazione personalizzata per il test di unità. O non si usa uno a tutti e si crea manualmente e iniettare i vostri fagioli.

Sembra a me come il test potrebbe essere un po 'troppo ampia. Unit testing è di circa di test, beh, unità. Un fagiolo primavera è un buon esempio di un'unità. Non dovrebbe essere necessario un contesto intera applicazione per questo. Trovo che se il test delle unità è così alto livello che avete bisogno di centinaia di fagioli, le connessioni al database, ecc allora avete una prova di unità davvero fragile che sta per rompere il successivo cambiamento, sarà difficile da mantenere e veramente isn' t l'aggiunta di un sacco di valore.

È possibile utilizzare il href="http://static.springframework.org/spring/docs/2.5.x/reference/beans.html" rel="nofollow noreferrer"> funzione

Non ho i punti reputazione ad accumulare risposta di duffymo, ma volevo solo a suonare e dire la sua era la risposta "giusta" per me.

un'istanza di un FileSystemXmlApplicationContext nella configurazione del test di unità con un applicationContext.xml personalizzato. In quel XML personalizzato, in alto, fare una come duffymo indica. Quindi dichiarare i vostri fagioli finto, fonti di dati non-JNDI, ecc, che sostituiranno le id dichiarati nella importazione.

Ha lavorato come un sogno per me.

Forse si potrebbe utilizzare qualificazioni per i vostri fagioli? Si potrebbe ridefinire i fagioli che si desidera prendere in giro in un contesto un'applicazione separata ed etichettarli con un "test" di qualificazione. Nei vostri test di unità, durante il cablaggio vostri fagioli specificare sempre il qualificatore "test" per utilizzare i mock up.

voglio fare la stessa cosa, e stiamo trovando indispensabile.

L'attuale meccanismo che usiamo è abbastanza manuale, ma funziona.

Dire per esempio, si vuole prendere in giro fuori di fagioli di tipo Y. Quello che facciamo è ogni chicco che ha che la dipendenza facciamo implementare un'interfaccia - "IHasY". Questa interfaccia è

interface IHasY {
   public void setY(Y y);
}

Poi, nel nostro test abbiamo chiamato il metodo util ...

 public static void insertMock(Y y) {
        Map invokers = BeanFactory.getInstance().getFactory("core").getBeansOfType(IHasY.class);
        for (Iterator iterator = invokers.values().iterator(); iterator.hasNext();) {
            IHasY invoker = (IHasY) iterator.next();
            invoker.setY(y);
        }
    }

Non voglio creare un file XML intero solo per iniettare questa nuova dipendenza ed è per questo che mi piace questo.

Se siete disposti a creare un file di configurazione XML quindi la strada da percorrere potrebbe essere quella di creare un nuovo stabilimento ai fagioli finte e rendere il vostro di fabbrica di un genitore di questa fabbrica. Assicuratevi quindi di caricare tutti i vostri fagioli dalla nuova fabbrica di bambino. Nel fare questo il sub-fabbrica avrà la precedenza i fagioli in fabbrica genitore quando l'ID di fagioli sono gli stessi.

Ora, se, nel mio test, se potessi a livello di codice di creare una fabbrica, sarebbe fantastico. Dovendo utilizzare XML è troppo ingombrante. Sto cercando di creare quella fabbrica bambino con il codice. Poi ogni test può configurare la sua fabbrica il modo in cui vuole. Non c'è alcun motivo per cui una fabbrica del genere non funzionerà.

molla reinject è progettato per sostituire fagioli con mock.

Poiché l'OP questo è arrivato lungo: Springockito

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top