Próbuję napisać test z użyciem spocka. Moja klasa która musi zostać przetestowana:
@AllArgsConstructor
public class Client {
private Parser parser;
public List<String> getParsedText() {
return parser.parse("foo");
}
}
Test napisany przy użyciu JUnit i Mockito:
@RunWith(MockitoJUnitRunner.class)
public class ClientTest {
@InjectMocks
private Client client;
@Mock
private Parser parser;
@Test
public void shouldReturnParsedText() {
// given
List<String> expectedResult = Collections.singletonList("result");
when(parser.parse(eq("foo"))
.thenReturn(expectedResult);
// when
List<String> result = client.getParsedText();
// then
assertEquals(result, expectedResult);
verify(parser, times(1)).parse(eq("foo"));
}
}
Ten sam test napisany przy użyciu Spock framework:
public class ClientSpec extends Specification {
def parser = Mock(Parser)
def client = new Client(parser)
def "should return parsed text"() {
given:
def expectedResult = ["result"];
parser.parse("foo") >> expectedResult;
when:
def result = client.getParsedText();
then:
result == expectedResult
1 * client.parse({
it == "foo"
})
}
Metoda parse() wykonana przez klasę Client zwraca null. Jeżeli napiszę kod jak poniżej, działa.
public class ClientSpec extends Specification {
def parser = Mock(Parser)
def client = new Client(parser)
def "should return parsed text"() {
given:
def expectedResult = ["result"];
when:
def result = client.getParsedText();
then:
result == expectedResult
1 * client.parse({
it == "foo"
}) >> expectedResult
}
Co ciekawe w tym przypadku then i clousure przekazane do parse wykonuje się przed wykonaniem faktycznego kodu. Dodatkowy problem z tym jest taki że mockujemy zachowanie metod w sekcji then, co jest niepoprawne.
Co może być przyczyną takiego zachowania spocka? Jak to naprawić. Nie będę ukrywał że testy napisane w spocku są o wiele ładniejsze i czytelniejsze.