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");
}
}