Rachid Calazans de Viveiros

July 23, 2021

RSpec Mock: Como retornar múltiplos valores para um mock

Uma das maneiras de fazer o mock de um object é utilizando o método allow do RSpec.

object = double

allow(object).to receive(:foo).and_return(11)

expect(object.foo).to be == 11

E quando sabemos que o método foo irá ser chamado múltiplas vezes (dentro de um loop por exemplo) e que o valor deve variar, como podemos fazer o mock disso?

O método and_return pode receber infinitos parâmetros, portanto podemos utilizar disso para retornar múltiplos resultados diferentes:

object = double

allow(object).to receive(:foo).and_return(11, 12)

expect(object.foo).to be == 11 # First call
expect(object.foo).to be == 12 # Second call
expect(object.foo).to be == 12 # Third call
expect(object.foo).to be == 12 # Fourth call

Note o seguinte, no and_return passamos apenas dois valores que devem ser retornados quando o object chamar o método foo. Isso significa o seguinte, quando o método foo for chamado a primeira vez, ele deverá retornar o valor 11. Quando for chamado da segunda vez em diante ele deverá retornar o valor 12, isso porque a partir da terceira chamada ele vai pegar o último valor adicionado como retorno do objeto mock.
 
Caso você precise fazer retorno múltiplo para chamadas de um mesmo método para diferentes parâmetros, o and_return com vários valores não será o suficiente, será necessário aplicar múltiplos allow:

object = double

allow(object).to receive(:buzz)
  .with('argument')
  .and_return(11, 12)

allow(object).to receive(:buzz)
  .with('argument_2')
  .and_return(13, 14)

# First call with 'argument'
expect(object.buzz('argument')).to be == 11

# Second call with 'argument'
expect(object.buzz('argument')).to be == 12

# Third call with 'argument'
expect(object.buzz('argument')).to be == 12

# First call with 'argument_2'
expect(object.buzz('argument_2')).to be == 13

# Second call with 'argument_2'
expect(object.buzz('argument_2')).to be == 14

# Third call with 'argument_2'
expect(object.buzz('argument_2')).to be == 14