2015-09-06 35 views
6

Sto programmando in ambiente Java SE usando WELD-SE per l'iniezione delle dipendenze. Pertanto dipendenze di una classe sono qualcosa del tipo:Come iniettare i mock durante il test delle classi usando CDI in produzione

public class ProductionCodeClass { 
    @Inject 
    private DependencyClass dependency; 
} 

Durante la scrittura di un test di unità per questa classe sto creando un mock per DependencyClass e come io non voglio iniziare un ambiente completo CDI per ogni prova corro , I "iniettare" il mock manualmente:

import static TestSupport.setField; 
import static org.mockito.Mockito.*; 

public class ProductionCodeClassTest { 
    @Before 
    public void setUp() { 
     mockedDependency = mock(DependencyClass.class); 
     testedInstance = new ProductionCodeClass(); 
     setField(testedInstance, "dependency", mockedDependency); 
    } 
} 

il metodo importato staticamente setField() io stesso ho scritto in una classe con gli strumenti che uso in fase di test:

public class TestSupport { 
    public static void setField(
           final Object instance, 
           final String field, 
           final Object value) { 
     try { 
      for (Class classIterator = instance.getClass(); 
       classIterator != null; 
       classIterator = classIterator.getSuperclass()) { 
       try { 
        final Field declaredField = 
           classIterator.getDeclaredField(field); 
        declaredField.setAccessible(true); 
        declaredField.set(instance, value); 
        return; 
       } catch (final NoSuchFieldException nsfe) { 
        // ignored, we'll try the parent 
       } 
      } 

      throw new NoSuchFieldException(
         String.format(
          "Field '%s' not found in %s", 
          field, 
          instance)); 
     } catch (final RuntimeException re) { 
      throw re; 
     } catch (final Exception ex) { 
      throw new RuntimeException(ex); 
     } 
    } 
} 

Quello che non mi piace di questa soluzione è che ho bisogno di questo aiuto più e più volte in ogni nuovo progetto. L'ho già impacchettato come progetto Maven che posso aggiungere come dipendenza di prova ai miei progetti.

Ma non c'è qualcosa di già pronto in qualche altra libreria comune che mi manca? Qualche commento sul mio modo di farlo in generale?

+0

Utilizzare l'iniezione del costruttore. – chrylis

risposta

7

Mockito supporta questa out of the box:

public class ProductionCodeClassTest { 

    @Mock 
    private DependencyClass dependency; 

    @InjectMocks 
    private ProductionCodeClass testedInstance; 

    @Before 
    public void setUp() { 
     testedInstance = new ProductionCodeClass(); 
     MockitoAnnotations.initMocks(this); 
    } 

} 

Il @InjectMocks annotazione attiveranno iniezione di classi o interfacce deriso nella classe di test, in questo caso DependencyClass:

Mockito cerca di iniettare per tipo (usando il nome nel caso in cui i tipi sono gli stessi). Mockito non lancia nulla quando l'iniezione fallisce: dovrai soddisfare le dipendenze manualmente.

Qui, Sono anche utilizzando il @Mock annotazioni invece di chiamare mock(). Potresti ancora usare mock(), ma preferisco usare le annotazioni.

Come nota a margine, sono disponibili strumenti di riflessione, che supportano la funzionalità implementata in TestSupport. Uno di questi esempi è ReflectionTestUtils.

+0

Sì, questo è in realtà ciò per cui stavo chiudendo. Già provato e i risultati sembrano molto buoni. Non ho trovato questo ... ;-) Non sto usando Spring, quindi aggiungo solo per ottenere ReflectionTestUtils potrebbe essere un po 'pesante. Ma grazie anche per questo suggerimento. –

+0

@Magnilex: hai pensato di aggiungere o "@RunWith (MockitoJUnitRunner.class)" o "@Rule pubblica MockitoRule regola ..." al tuo codice per completarlo? – Henrik

+0

@ Henrik Il codice è completo. '@RunWith (MockitoJUnitRunner.class)' sarebbe un'alternativa però. Tuttavia, questa risposta spiega la domanda di OP: la domanda non è chiedere alternative su come eseguire un test JUnit basato su mockito. – Magnilex

1

alternativa quando mockitos costruire in funzioni non sono sufficienti: Prova needle4j.org

E 'un quadro di iniezione/finta che permette l'iniezione di schernisce e casi concreti e supporta anche postConstruct per la simulazione del ciclo di vita.

public class ProductionCodeClassTest { 

    @Rule 
    public final NeedleRule needle = new NeedleRule(); 

    // will create productionCodeClass and inject mocks by default 
    @ObjectUnderTest(postConstruct=true) 
    private ProductionCodeClass testedInstance; 

    // this will automatically be a mock 
    @Inject 
    private AServiceProductionCodeClassDependsOn serviceMock; 

    // this will be injected into ObjectUnderTest 
    @InjectIntoMany 
    private ThisIsAnotherDependencyOfProdcutionCodeClass realObject = new ThisIsAnotherDependencyOfProdcutionCodeClass(); 

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

} 
+0

Bello! C'è un progetto di esempio/una suite di test, per caso?Qualcosa come l'esempio di JMockit (https://github.com/jmockit/jmockit1/tree/master/samples/petclinic) sarebbe l'ideale. –

+0

Bene, ci sono alcuni esempi basati su 2.2, ma non li abbiamo migrati a 2.3 finora. Ma potrebbe essere utile: https://github.com/needle4j/needle/tree/master/src/examples –