Como usar o ArgumentCaptor para stubbing?

161

Na documentação do Mockito e javadocs, ele diz

É recomendável usar o ArgumentCaptor com verificação, mas não com stub.

mas não entendo como o ArgumentCaptor pode ser usado para stub. Alguém pode explicar a declaração acima e mostrar como o ArgumentCaptor pode ser usado para stubbing ou fornecer um link que mostra como isso pode ser feito?

Não posso dizer
fonte
1
Explicação super curta e agradável aqui: dzone.com/articles/…
Benj

Respostas:

271

Assumindo o seguinte método para testar:

public boolean doSomething(SomeClass arg);

A documentação do Mockito diz que você não deve usar o captor desta maneira:

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));

Porque você pode apenas usar o matcher durante o stub:

when(someObject.doSomething(eq(expected))).thenReturn(true);

Mas a verificação é uma história diferente. Se seu teste precisar garantir que esse método foi chamado com um argumento específico, use ArgumentCaptore este é o caso para o qual foi projetado:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));
Rorick
fonte
Obrigado pela resposta. Eu tenho uma pergunta. No terceiro bloco de código, sabemos que true é retornado apenas quando o esperado é passado para doSomething. Mas quando é retornado true no segundo bloco de código? Ou someObject sempre retorna true para someMethod nesse caso?
Não posso dizer
Hum, acredito que você quis dizer "Mas quando é verdade retornada no terceiro bloco de código?". No terceiro bloco de código, simplesmente não ligamos para o valor de retorno e deixamos que seja o padrão. Para booleano false, não é true.
Rorick
Não, contei todos os blocos de fundo cinza como blocos de código. Incluindo o primeiro revestimento. Eu estava me referindo à linha when (someObject.doSomething (argumentCaptor.capture ())). ThenReturn (true);
Não posso dizer
Ah desculpa. Sim, neste caso, true será retornado sempre.
Rorick
3
Não tenho certeza se o motivo para "não usar com stub" é um motivo simples. os matchers não nos dão o argumento esperado real (apenas o tipo) e levam à aprovação dos testes, apesar dos argumentos que podem estar errados.
dtc
0

A linha

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

faria o mesmo que

when(someObject.doSomething(Matchers.any())).thenReturn(true);

Portanto, usar o argumentoCaptor.capture () quando o stubbing não tem valor agregado. O uso de Matchers.any () mostra melhor o que realmente acontece e, portanto, é melhor para facilitar a leitura. Com argumentCaptor.capture (), você não pode ler quais argumentos são realmente correspondidos. E, em vez de usar any (), você pode usar correspondências mais específicas quando tiver mais informações (classe do argumento esperado), para melhorar seu teste.

E outro problema: se você usar o argumentoCaptor.capture () ao fazer stub, fica claro quantos valores você deve esperar que sejam capturados após a verificação. Queremos capturar um valor durante a verificação, não durante o stub, porque nesse momento ainda não há valor para capturar. Então, o que os captores de argumento capturam a captura do método durante o stub? ou não captura nada? Eu não tenho a resposta para esta pergunta. Considero um comportamento indefinido e não quero usar um comportamento indefinido.

Stefan Mondelaers
fonte
0

Hipoteticamente, se a pesquisa o levou a essa pergunta, provavelmente você deseja o seguinte:

doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));

Por quê? Porque, como eu, você valoriza o tempo e não implementará .equalsapenas por uma questão de cenário de teste único.

E 99% dos testes desmoronam com retorno nulo da Mock e, em um design razoável, você evita o retorno nulla todo custo, usa Optionalou muda para o Kotlin. Isso implica que verifynão precisa ser usado com freqüência e os ArgumentCaptors são muito entediantes para escrever.

Beringela
fonte