2016-03-18 9 views
9

Ho uno Spring MVC @Controller con questo costruttore:Iniettando una proprietà String con @InjectMocks

@Autowired 
public AbcController(XyzService xyzService, @Value("${my.property}") String myProperty) {/*...*/} 

Voglio scrivere un test di unità standalone per questo controller:

@RunWith(MockitoJUnitRunner.class) 
public class AbcControllerTest { 

    @Mock 
    private XyzService mockXyzService; 

    private String myProperty = "my property value"; 

    @InjectMocks 
    private AbcController controllerUnderTest; 

    /* tests */ 
} 

C'è un modo ottenere @InjectMocks per iniettare la mia proprietà String? So che non posso prendere in giro una stringa dal momento che è immutabile, ma posso semplicemente inserire una stringa normale qui?

@InjectMocks inietta un valore di default in questo caso. @Mock getta comprensibilmente un'eccezione se la metto su myProperty. C'è un'altra annotazione che mi è sfuggita che significa semplicemente "iniettare questo oggetto esatto piuttosto che un Mock di esso"?

+0

So che posso istanziare solo manualmente il mio controller in un metodo di impostazione, ma spero di trovare una soluzione nello stile di configurazione delle annotazioni. Grazie! –

risposta

4

Non puoi farlo con Mockito, perché, come hai detto tu stesso, un String è final e non può essere deriso.

C'è un'annotazione @Spy che funziona su reali oggetti, ma ha le stesse limitazioni di @Mock, quindi non si può spiare un String.

Non ci sono annotazioni per dire a Mockito di iniettare quel valore senza fare il tifo o lo spionaggio. Sarebbe una buona caratteristica, però. Forse suggerirlo allo Mockito Github repository.

È necessario creare manualmente un'istanza del controller se non si desidera modificare il codice.

L'unico modo per avere un test basato su annotazione pura è il refactoring del controller. Può utilizzare un oggetto personalizzato che contiene solo quella proprietà, o forse una classe di configurazione con proprietà multiple.

@Component 
public class MyProperty { 

    @Value("${my.property}") 
    private String myProperty; 

    ... 
} 

Questo può essere iniettato nel controller.

@Autowired 
public AbcController(XyzService xyzService, MyProperty myProperty) { 
    ... 
} 

È possibile prendere in giro e inietta questo poi.

@RunWith(MockitoJUnitRunner.class) 
public class AbcControllerTest { 

    @Mock 
    private XyzService mockXyzService; 

    @Mock 
    private MyProperty myProperty; 

    @InjectMocks 
    private AbcController controllerUnderTest; 

    @Before 
    public void setUp(){ 
     when(myProperty.get()).thenReturn("my property value"); 
    } 

    /* tests */ 
} 

Questo non è piuttosto semplice, ma almeno si sarà in grado di avere un test basato un'annotazione puro con un po 'di sradicamento.

+1

Questo è sfortunato. Ho esaminato il loro strumento di emissione e sembra che abbiano [discusso] (https://github.com/mockito/mockito/issues/174) [prima] (https://github.com/mockito/Mockito/tirare/277). L'idea generale sembra essere che sia fuori portata per un quadro beffardo, e forse anche un odore di codice, anche se non credo di essere d'accordo. Grazie per il vostro aiuto! –

9

Non è possibile farlo con Mockito, ma Apache Commons ha in realtà un modo per farlo utilizzando una delle sue utilità incorporate. Si può mettere questo in una funzione in JUnit che viene eseguito dopo Mockito inietta il resto dei mock, ma prima che i vostri casi di test eseguire, in questo modo:

@InjectMocks 
MyClass myClass; 

@Before 
public void before() throws Exception { 
    FieldUtils.writeField(myClass, "fieldName", fieldValue, true); 
}