O que é zombar?

Respostas:

598

Prólogo: se você procurar o substantivo mock no dicionário, verá que uma das definições da palavra é algo feito como uma imitação .


A zombaria é usada principalmente em testes de unidade. Um objeto em teste pode ter dependências em outros objetos (complexos). Para isolar o comportamento do objeto, você deseja substituir os outros objetos por zombarias que simulam o comportamento dos objetos reais. Isso é útil se os objetos reais não forem práticos para incorporar no teste de unidade.

Em resumo, zombar é criar objetos que simulam o comportamento de objetos reais.


Às vezes, você pode distinguir entre zombar e não fazer stub . Pode haver algum desacordo sobre esse assunto, mas minha definição de esboço é um objeto simulado "mínimo". O stub implementa apenas o comportamento suficiente para permitir que o objeto em teste execute o teste.

Uma simulação é como um esboço, mas o teste também verificará se o objeto em teste chama a simulação conforme o esperado. Parte do teste está verificando se o mock foi usado corretamente.

Para dar um exemplo: Você pode stub um banco de dados implementando uma estrutura simples na memória para armazenar registros. O objeto em teste pode ler e gravar registros no stub do banco de dados para permitir a execução do teste. Isso poderia testar algum comportamento do objeto não relacionado ao banco de dados e o stub do banco de dados seria incluído apenas para permitir a execução do teste.

Se você deseja verificar se o objeto em teste grava alguns dados específicos no banco de dados, será necessário zombar do banco de dados. Seu teste incorporaria asserções sobre o que foi gravado na simulação do banco de dados.

Martin Liversage
fonte
18
Essa é uma boa resposta, mas restringe desnecessariamente o conceito de zombaria a objetos . Substituir "objeto" por "unidade" o tornaria mais geral.
Rogério
1
Eu entendo a diferença entre esboço versus simulação. A única coisa é que, se você estiver testando seus casos com um stub e ele passar, não será possível concluir que você já está usando o stub e, portanto, não precisará mais da verificação ?
Mel
91

Outras respostas explicam o que é zombaria. Deixe-me guiá-lo através dele com diferentes exemplos . E acredite, é realmente muito mais simples do que você pensa.

tl; dr É uma instância da classe original. Ele possui outros dados injetados, para que você evite testar as peças injetadas e se concentre apenas em testar os detalhes de implementação de sua classe / funções.

Um exemplo simples:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Como você pode ver, não estou testando a Linha A, ou seja, não estou validando os parâmetros de entrada. Não estou validando para ver se num1, num2 é um número inteiro. Não tenho afirmações contra isso.

Estou apenas testando para ver se a LineB (minha implementação ) forneceu os valores simulados 1e 5está fazendo o que eu esperava.

Obviamente, na palavra real, isso pode se tornar muito mais complexo. Os parâmetros podem ser um objeto personalizado, como Pessoa, Endereço ou os detalhes da implementação podem ser mais do que um único +. Mas a lógica dos testes seria a mesma.

Exemplo sem codificação:

Suponha que você esteja construindo uma máquina que identifique o tipo e o nome da marca de dispositivos eletrônicos para segurança do aeroporto. A máquina faz isso processando o que vê com sua câmera.

Agora, seu gerente entra pela porta e pede que você faça um teste de unidade.

Então, como desenvolvedor, você pode trazer 1000 objetos reais, como um MacBook pro, Google Nexus, uma banana, um iPad etc. na frente dele e testar e ver se tudo funciona.

Mas você também pode usar objetos simulados , como um MacBook pro de aparência idêntica (sem partes internas reais) ou uma banana plástica na frente dele. Você pode evitar investir em 1000 laptops reais e bananas podres.

O ponto é que você não está tentando testar se a banana é falsa ou não. Nem testando se o laptop é falso ou não. Tudo o que você está fazendo é testar se sua máquina, uma vez que vê uma banana que diria not an electronic devicee para um MacBook Pro diria: Laptop, Apple. Para a máquina, o resultado de sua detecção deve ser o mesmo para eletrônicos falsos / simulados e eletrônicos reais

A lógica mencionada acima também se aplica ao teste de unidade do código real. Essa é uma função que deve funcionar da mesma forma com valores reais obtidos com entradas reais (e interações) ou zombadosvalores que você injeta durante o teste de unidade. E da mesma maneira que você evita o uso de uma banana ou MacBook real, com testes de unidade (e zombaria), evita fazer algo que faça com que o servidor retorne um código de status 500, 403, 200, etc. (forçando seu servidor para disparar 500 é apenas quando o servidor está inoperante, enquanto o servidor 200 está ativo.Fica difícil executar 100 testes focados na rede se você precisar esperar constantemente 10 segundos entre alternar entre o servidor ativo e inativo). Então, em vez disso, você injeta / zomba de uma resposta com o código de status 500, 200, 403, etc. e testa sua unidade / função com um valor injetado / zombado.

Exemplo de codificação:

Digamos que você esteja escrevendo um aplicativo iOS e tenha chamadas de rede. Seu trabalho é testar seu aplicativo. Testar / identificar se as chamadas de rede funcionam ou não conforme o esperado NÃO É SUA RESPONSABILIDADE. É responsabilidade de outra parte (equipe do servidor) testá-lo. Você deve remover essa dependência (de rede) e, ainda assim, continuar testando todo o seu código que funciona em torno dela.

Uma chamada de rede pode retornar diferentes códigos de status 404, 500, 200, 303, etc. com uma resposta JSON.

Seu aplicativo deve funcionar para todos eles (em caso de erros, ele deve gerar o erro esperado). O que você faz com zombaria é criar respostas de rede 'imaginárias - semelhantes às reais' (como um código 200 com um arquivo JSON) e testar seu código sem 'fazer a chamada de rede real e aguardar sua resposta de rede'. Você codifica / devolve manualmente a resposta de rede para TODOS os tipos de respostas de rede e verifica se seu aplicativo está funcionando conforme o esperado. (você nunca assume / testa um 200 com dados incorretos, porque isso não é de sua responsabilidade, sua responsabilidade é testar seu aplicativo com um 200 correto ou, no caso de 400, 500, você testa se o aplicativo gera o erro correto)

Esse imaginário criador - semelhante ao real é conhecido como zombaria.

Para fazer isso, você não pode usar seu código original (seu código original não possui as respostas pré-inseridas, certo?). Você deve adicionar algo a ele, injetar / inserir os dados fictícios que normalmente não são necessários (ou parte de sua classe).

Então você cria uma instância da classe original e adicionar o que (aqui é a rede HTTPResponse, dados ou, no caso de falha, você passa o errorString correta, HTTPResponse) você precisa-lo e, em seguida, testar o zombou classe.

Para encurtar a história, zombar é simplificar e limitar o que você está testando e também fazer você alimentar o que uma classe depende. Neste exemplo, você evita testar as próprias chamadas de rede e, em vez disso, testa se o aplicativo funciona ou não conforme o esperado com as saídas / respostas injetadas - zombando de classes

Escusado será dizer que você testa cada resposta de rede separadamente.


Agora, uma pergunta que eu sempre tinha em mente era: Os contratos / pontos finais e basicamente a resposta JSON das minhas APIs são atualizados constantemente. Como posso escrever testes de unidade que levam isso em consideração?

Para elaborar mais sobre isso: digamos que o modelo exija uma chave / campo nomeado username. Você testa isso e seu teste passa. Duas semanas depois, o back-end altera o nome da chave para id. Seus testes ainda passam. direita? ou não?

É responsabilidade do desenvolvedor de back-end atualizar as zombarias. Deveria fazer parte do nosso acordo que eles fornecem zombarias atualizadas?

A resposta para a questão acima é que: testes de unidade + seu processo de desenvolvimento como desenvolvedor do lado do cliente / deveriam receber respostas falsas desatualizadas. Se você me perguntar como? bem, a resposta é:

Nosso aplicativo atual falharia (ou não falhará, ainda não possui o comportamento desejado) sem o uso de APIs atualizadas ... portanto, se isso falhar ... faremos alterações em nosso código de desenvolvimento. O que novamente leva ao fracasso de nossos testes ... e nós vamos ter que corrigi-lo. (Na verdade, se formos fazer o processo TDD corretamente, não escreveremos nenhum código sobre o campo, a menos que escrevamos o teste para ele ... e o veremos falhar e, em seguida, escreveremos o código de desenvolvimento real.)

Isso tudo significa que o back-end não precisa dizer: “ei, nós atualizamos os simulados” ... isso eventualmente acontece através do desenvolvimento / depuração do código. ‌ّ Porque tudo faz parte do processo de desenvolvimento! Embora se o back-end fornecer a resposta zombada para você, será mais fácil.

Meu ponto principal é que (se você não pode automatizar a atualização da resposta da API simulada ), é necessária alguma interação humana, ou seja, atualizações manuais de JSONs e reuniões curtas para garantir que seus valores estejam atualizados se tornarão parte de seu processo

Esta seção foi escrita graças a uma discussão superficial no nosso grupo de reuniões do CocoaHead


Apenas para desenvolvedores iOS:

Um bom exemplo de zombaria é essa palestra sobre protocolo prático de Natasha Muraschev . Pule para o minuto 18:30, embora os slides possam ficar fora de sincronia com o vídeo real 🤷‍♂️

Eu realmente gosto desta parte da transcrição:

Como isso está testando ... queremos ter certeza de que a getfunção do Gettableé chamada, porque ela pode retornar e, em teoria, a função pode atribuir uma variedade de itens alimentares de qualquer lugar . Precisamos ter certeza de que é chamado;

Mel
fonte
3
Ótimo exemplo, eu apenas acrescentaria que, neste exemplo em particular, a subclasse age como uma farsa, mas este exemplo também usa stubbing. As respostas JSON codificadas são consideradas respostas stubbed. Só adiciono isso porque pode ser difícil diferenciar entre zombarias e stubs, mas este exemplo mostra claramente como ambos podem ser usados ​​juntos.
user3344977
Excelente explicação, obrigado. Um pequeno ajuste na pergunta sobre a alteração da API. E se não for sua API, para que você não faça parte do processo de desenvolvimento? Quero saber quando minha biblioteca cliente está falhando.
precisa
@ThinkDigital Os bons fornecedores de API têm boas notas de versão e comunicam as alterações corretamente, se você não tiver esse canal, talvez seja hora de você participar de uma reunião e discuti-lo | bons desenvolvedores sempre analisam as alterações na API de uma nova versão e evitam apenas atualizar a versão da API. Você tem versões da API? Se nenhum deles entender, então, após o controle de qualidade, você descobrirá, atualize seus testes ← dever de toda a equipe. → dever de um único desenvolvedor: não deve se importar muito. Apenas lide com o caso em que o servidor retorne um erro ou o servidor não retorne um erro, mas não possa analisar o json ou lide com o caso correto.
Honey
Obrigado por responder, @Mel! No meu caso, estou mantendo um cliente para pub.dev , que tem uma API, mas está faltando muito. Tanto que era melhor criar uma API raspando o site, do que usar a API oficial. Por esse motivo, as alterações no site podem quebrar o código e não precisam se preocupar em atualizar ninguém nesse caso. O site é de código aberto, mas é diferente manter uma API baseada em alterações feitas de maneira mais trivial.
ThinkDigital
32

Há muitas respostas no SO e boas postagens na web sobre zombaria. Um lugar que você pode querer começar a procurar é o post de Martin Fowler Mocks não são stubs, onde ele discute muitas das idéias de zombaria.

Em um parágrafo - Zombar é uma técnica específica para permitir o teste de uma unidade de código sem depender de dependências. Em geral, o que diferencia a simulação de outros métodos é que objetos simulados usados ​​para substituir dependências de código permitirão que as expectativas sejam definidas - um objeto simulado saberá como deve ser chamado pelo seu código e como responder.


Sua pergunta original mencionou o TypeMock, então deixei minha resposta abaixo:

TypeMock é o nome de uma estrutura de zombaria comercial .

Ele oferece todos os recursos das estruturas de zombaria gratuitas, como RhinoMocks e Moq, além de algumas opções mais poderosas.

Se você precisa ou não do TypeMock, é altamente discutível - você pode fazer a maioria das zombarias que desejar com as bibliotecas de zombaria gratuitas, e muitos argumentam que as habilidades oferecidas pela TypeMock geralmente o afastam de um design bem encapsulado.

Como outra resposta declarada, 'TypeMocking' não é, na verdade, um conceito definido, mas pode ser entendido como o tipo de zombaria que o TypeMock oferece, usando o criador de perfil CLR para interceptar chamadas .Net em tempo de execução, dando uma capacidade muito maior a objetos falsos (não requisitos) como a necessidade de interfaces ou métodos virtuais).

David Hall
fonte
@Masoud nunca mencionou o TypeMock. Sua pergunta era sobre "zombaria de tipos" em geral.
Peter Lillevold
4
@ Peter - como outro comentário disse, verifique o histórico de edições da pergunta. Não posso fazer muito se eu postar uma resposta e a pergunta original for completamente alterada.
19410 David Hall
9

Mock é um método / objeto que simula o comportamento de um método / objeto real de maneira controlada. Objetos simulados são usados ​​no teste de unidade.

Geralmente, um método em teste chama outros serviços ou métodos externos. Isso é chamado de dependências. Uma vez zombadas, as dependências se comportam da maneira como as definimos.

Com as dependências sendo controladas por zombarias, podemos facilmente testar o comportamento do método que codificamos. Este é o teste de unidade.

Qual é o objetivo dos objetos simulados?

Mocks vs stubs

Testes de unidade vs testes funcionais

Venkat Kotra
fonte
7

A zombaria está gerando pseudo-objetos que simulam o comportamento de objetos reais para testes

ri muito
fonte
5

O objetivo dos tipos de simulação é separar as dependências para isolar o teste em uma unidade específica. Os stubs são substitutos simples, enquanto os zombadores são substitutos que podem verificar o uso. Uma estrutura de simulação é uma ferramenta que o ajudará a gerar stubs e zombarias.

EDIT : Como o texto original menciona "tipo de zombaria", tive a impressão de que isso estava relacionado ao TypeMock. Na minha experiência, o termo geral é apenas "zombaria". Sinta-se à vontade para desconsiderar as informações abaixo especificamente no TypeMock.

O TypeMock Isolator difere da maioria dos outros frameworks de simulação, pois funciona minha modificação da IL em tempo real. Isso permite zombar de tipos e instâncias que a maioria das outras estruturas não pode zombar. Para zombar desses tipos / instâncias com outras estruturas, você deve fornecer suas próprias abstrações e zombar delas.

O TypeMock oferece grande flexibilidade às custas de um ambiente de tempo de execução limpo. Como efeito colateral da maneira como o TypeMock alcança seus resultados, às vezes você obtém resultados muito estranhos ao usar o TypeMock.

Brian Rasmussen
fonte
@Masoud nunca mencionou o TypeMock. Sua pergunta era sobre "zombaria de tipos" em geral.
Peter Lillevold
1
@ Peter: O texto original era "o que é zombaria?".
21410 Brian
Eu sei. Como "simulação de tipo" não é equivalente a "TypeMock", acho que a sua e a resposta @Oded estão completamente erradas.
Peter Lillevold 19/04/10
1
@ Peter: Na minha experiência, o termo geral é "zombaria", mas, em qualquer caso, atualizei minha resposta para, com sorte, tornar isso claro. Obrigado pela contribuição.
27710 Brian
3

Eu acho que o uso da estrutura de simulação do isolador TypeMock seria TypeMocking.

É uma ferramenta que gera simulações para uso em testes de unidade, sem a necessidade de escrever seu código com a IoC em mente.

Oded
fonte
@Masoud nunca mencionou o TypeMock. Sua pergunta era sobre "zombaria de tipos" em geral.
Peter Lillevold
3
Na verdade, a pergunta original incluía a palavra "Type" antes de "Mocking", mas depois foi editada. É por isso que algumas das respostas contêm informações específicas sobre o TypeMock.
Martin Liversage
1

Se o seu mock envolve uma solicitação de rede, outra alternativa é ter um servidor de teste real a ser atingido. Você pode usar este serviço para gerar uma solicitação e resposta para seu teste. http://testerurl.com/

foobar8675
fonte
Eu apenas tentei acessá-lo e levou vários minutos. Quem pode dizer que também não está registrando solicitações secretamente? Finalmente, este pode ser melhor como um comentário :)
Kieren Johnstone
Na verdade, eu o derrubei, pois não tinha vontade de transferi-lo para uma hospedagem gratuita. Sim, isso deveria ter sido um comentário. é de código aberto; portanto, se houver uma preocupação com as solicitações de log, você poderá executar por conta própria. github.com/captainchung/TesterUrl
Matthew Chung