Ostatnio zdażyło mi się trafić na dosyć intrygujący problem: testy junitowe odpalane były poprzez runner’a spring’owego co umożliwiało wstrzykiwanie zależności poprzez config testowy. No ale to wszyscy znamy – problem pojawił w momencie gdy chciałem dodać runner’a mockito’wego gdyż adnotacja @RunWith nie oferuje takiej możliwości, no i już byłem przekonany, że trzeba będzie zakasać rękawy i napisać jakieś api np. z użyciem dekoratora, ale jak zwykle wyszedł ze mnie leń i postanowiłem sprawdzić czy ktoś już tego czasem nie zrobił.
Okazało się, że nie, ale ze względu na to, że @RunWith została dodana nieco późno i nie była do końca przemyślana. W junit’cie 4.7 wprowadzono tzw. Intereceptors ale zmieniono ich nazwę wraz z wersją 4.8 na Rule.
Co daje nam ta adnotacja – możemy ją zaaplikować do publicznej własności naszego testu, i musi on implementować interfejs MethodRule. Reszta to już bułeczka z masełkiem – MethodRule zwraca Statement‚a, który w działaniu przypomina nieco advice’a Around, znanego użytkownikom AOP – zawijamy sobie statement, wywołujemy co nam trzeba, następnie execute na oryginale i już. Dla przykładu stwórzmy taka klase, która pozwoli nam tworzyć mocki, mockitowe z wykorzystaniem adnotacji @Mock.
package pl.bedkowski.code.rules; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.mockito.MockitoAnnotations; public class InitMocks implements MethodRule { public Statement apply(final Statement stmt, FrameworkMethod arg1, final Object arg2) { return new Statement(){ @Override public void evaluate() throws Throwable { MockitoAnnotations.initMocks(arg2); stmt.evaluate(); }}; } }
No i jakis przykladowy tescik:
package pl.bedkowski.code.rules; import static org.mockito.Mockito.when; import org.junit.Rule; import org.junit.Test; import org.junit.rules.MethodRule; import org.mockito.Mock; interface SomeInterface{ String doSmth(); } public class SampleTest { @Rule public MethodRule i = new InitMocks(); @Mock private SomeInterface my; @Test public void testing() throws Exception { when(my.doSmth()).thenReturn("33"); } }