Qual é a diferença entre um mock e esboço?


963

Eu li vários artigos sobre zombaria ou stubbing em testes, incluindo Mocks Arn't Stubs , de Martin Fowler , mas ainda não entendo a diferença.



75
@OP Porque não há diferença. Este artigo, por mais amado pela comunidade, está - com todo o respeito - tornando tudo desnecessário confuso, adicionando significado adicional a palavras que são fáceis de entender de outra forma e tornando as coisas desnecessárias complicadas. Mock é apenas uma farsa, algo que executa uma lógica de negócios falsa, em vez da lógica real. Verificar comportamento no final é sua escolha, mas ainda é uma farsa. Ou o que você quiser chamar, mas faça UM. Não separe os cabelos. Mantenha-o simples, para que as pessoas possam entender seu conceito facilmente - com o que o artigo acima falha.
wst

10
"A classificação entre zombarias, falsificações e stubs é altamente inconsistente em toda a literatura." Com muitas citações. Ainda é uma das minhas citações favoritas da Wikipedia - se isso existe :) en.wikipedia.org/wiki/Mock_object
JD.

11
que o artigo de Martin Fowler é realmente difícil de entender para iniciantes.
Lmiguelvargasf

1
Pelo que entendi, um stub seria apenas um objeto descartável para o seu teste, como uma coleção de dados fictícios. Um Mock seria uma versão habilmente substituída de algo mais complexo, como uma camada de serviço com vários métodos, dos quais você pode ter alterado o comportamento de seus testes. As duas coisas são usadas juntas, como se você pudesse passar alguns objetos stubbed para sua camada de simulação.
JsonStatham

Respostas:


746

Stub

Acredito que a maior distinção é que um esboço que você já escreveu com comportamento predeterminado. Portanto, você teria uma classe que implementa a dependência (classe abstrata ou interface mais provável) que você está falsificando para fins de teste e os métodos seriam eliminados com respostas definidas. Eles não fariam nada sofisticado e você já teria escrito o código stubbed fora do teste.

Zombar

Um mock é algo que, como parte de seu teste, você precisa configurar com suas expectativas. Uma simulação não é configurada de maneira predeterminada, portanto você tem um código que faz isso em seu teste. De certa forma, as zombarias são determinadas em tempo de execução, pois o código que define as expectativas precisa ser executado antes que elas façam alguma coisa.

Diferença entre zombarias e stubs

Testes escritos com zombarias geralmente seguem um initialize -> set expectations -> exercise -> verifypadrão para testes. Enquanto o esboço pré-escrito seguiria um initialize -> exercise -> verify.

Semelhança entre zombarias e stubs

O objetivo de ambos é eliminar o teste de todas as dependências de uma classe ou função, para que seus testes sejam mais focados e mais simples no que eles estão tentando provar.


876

Prefácio

Existem várias definições de objetos que não são reais. O termo geral é teste duplo . Este termo abrange: manequim , falso , esboço , simulação .

Referência

De acordo com o artigo de Martin Fowler :

  • Objetos fictícios são passados, mas nunca são realmente usados. Geralmente eles são usados ​​apenas para preencher listas de parâmetros.
  • Objetos falsos realmente têm implementações de trabalho, mas geralmente usam algum atalho que os torna inadequados para produção (um banco de dados na memória é um bom exemplo).
  • Os stubs fornecem respostas prontas para as chamadas feitas durante o teste, geralmente não respondendo a nada fora do que está programado para o teste. Os stubs também podem registrar informações sobre chamadas, como um stub de gateway de e-mail que lembra as mensagens "enviadas" ou talvez apenas quantas mensagens foram "enviadas".
  • Zombamos é o que estamos falando aqui: objetos pré-programados com expectativas que formam uma especificação das chamadas que eles devem receber.

Estilo

Mocks vs Stubs = teste comportamental x teste estadual

Princípio

De acordo com o princípio do teste, apenas uma coisa por teste , pode haver vários stubs em um teste, mas geralmente há apenas uma simulação.

Ciclo da vida

Teste o ciclo de vida com stubs:

  1. Instalação - Prepare o objeto que está sendo testado e seus stubs colaboradores.
  2. Exercício - Teste a funcionalidade.
  3. Verificar estado - use declarações para verificar o estado do objeto.
  4. Desmontagem - Limpe os recursos.

Teste o ciclo de vida com zombarias:

  1. Dados da instalação - Prepare o objeto que está sendo testado.
  2. Expectativas de configuração - prepare as expectativas em simulação que estão sendo usadas pelo objeto principal.
  3. Exercício - Teste a funcionalidade.
  4. Verificar expectativas - Verifique se os métodos corretos foram invocados com simulação.
  5. Verificar estado - use declarações para verificar o estado do objeto.
  6. Desmontagem - Limpe os recursos.

Sumário

Os testes de zombaria e stubs respondem à pergunta: Qual é o resultado?

Testes com zombarias também estão interessados ​​em: Como o resultado foi alcançado?


Espere, as zombarias também retornam respostas em lata? Causar o contrário, por que eles respondem à pergunta?
AturSams

Pelo que você escreveu, posso dizer que zombarias = stubs + expectativas e verificações, porque zombam "fornecem respostas prontas para chamadas feitas durante o teste, geralmente não respondendo a nada fora do que está programado para o teste" (o mesmo que stubs). E o exemplo que Fowler mostrou como exemplo de um esboço é realmente um exemplo de espião! Isso significa que um mock é um esboço e um espião é um esboço. E um esboço é apenas um objeto que possui vários métodos de trabalho. Isso também explica por que o Mockito reprovou o método stub ().
Kolobok

O que eu acho confuso sobre isso e a resposta aceita é esse "cenário de expectativas", o que isso significa? Normalmente, no "código principal", você cria os resultados que esperaria. Parece que você coloca as expectativas de alguma forma no objeto falso, o que não faz sentido para mim. Além disso, você poderia facilmente exercitar o mock com alguma entrada, armazenar o resultado, criar "as expectativas" mais tarde e depois comparar. Você usa terminologia que eu acho muito abstrata e ambígua.
IceFire

365

Um esboço é um objeto falso simples. Apenas garante que o teste seja executado sem problemas.
Um mock é um esboço mais inteligente. Você verifica se o seu teste passa por ele.


33
Eu acho que essa é a resposta mais sucinta e pontual. Takeaway: um esboço IS-A simulado. stackoverflow.com/a/17810004/2288628 é a versão mais longa desta resposta.
PoweredByRice

8
Não acho que uma zombaria seja um esboço. As zombarias são usadas para afirmar e nunca devem retornar dados, os stubs são usados ​​para retornar dados e nunca devem afirmar.
Dave1010

2
@ dave1010 Mocks definitivamente podem retornar dados ou até lançar uma exceção. Eles devem fazê-lo em resposta aos parâmetros passados ​​para eles.
Trenton

2
@trenton se um objeto retorna ou joga com base nos dados passados, então é uma farsa , não uma farsa . Os stubs testam como o SUT lida com o recebimento de mensagens, os zombadores testam como o SUT envia mensagens. Misturar os 2 provavelmente levará a um projeto de OO ruim.
precisa saber é o seguinte

8
Eu acho que isso é ótimo - um esboço retorna respostas para as perguntas. Um mock também retorna respostas às perguntas (é um esboço), mas também verifica se a pergunta foi feita !!
Leif

238

Aqui está uma descrição de cada um seguido por uma amostra do mundo real.

  • Manequim - apenas valores falsos para satisfazer o API.

    Exemplo : se você estiver testando um método de uma classe que requer muitos parâmetros obrigatórios em um construtor que não afetam seu teste, poderá criar objetos fictícios com o objetivo de criar novas instâncias de uma classe.

  • Falso - crie uma implementação de teste de uma classe que possa depender de alguma infraestrutura externa. (É uma boa prática que seu teste de unidade NÃO realmente interaja com a infraestrutura externa.)

    Exemplo : Crie uma implementação falsa para acessar um banco de dados, substitua-o por in-memorycoleção.

  • Stub - substitui métodos para retornar valores codificados, também chamados de state-based.

    Exemplo : Sua classe de teste depende de um método que Calculate()leva 5 minutos para ser concluído. Em vez de aguardar 5 minutos, você pode substituir sua implementação real por stub que retorna valores codificados; levando apenas uma pequena fração do tempo.

  • Mock - muito parecido, Stubmas interaction-basednão baseado no estado. Isso significa que você não espera Mockque retorne algum valor, mas suponha que uma ordem específica de chamadas de método seja feita.

    Exemplo: você está testando uma classe de registro de usuário. Depois de ligar Save, deve ligar SendConfirmationEmail.

Stubse Mockssão, na verdade, subtipos de Mock, ambos trocam implementação real com implementação de teste, mas por diferentes motivos específicos.


175

No curso codeschool.com , Rails Testing for Zombies , eles fornecem esta definição dos termos:

Stub

Para substituir um método por código que retorna um resultado especificado.

Zombar

Um stub com uma asserção de que o método é chamado.

Então, como Sean Copenhaver descreveu em sua resposta, a diferença é que a zombaria estabelece expectativas (ou seja, faz afirmações sobre se ou como elas são chamadas).


Para complementar a publicação de Dillon, pense sobre isso: você tem uma classe chamada "MakeACake", que pega várias bibliotecas: leite, ovos, açúcar, forno.
aarkerio

139

Os stubs não são reprovados em seus testes, podem sim.


2
E acho que isso é bom, você sabe se os testes têm o mesmo comportamento após a refatoração.
RodriKing

1
@RodriKing Eu tenho o mesmo sentimento. Como no Mock, com qualquer alteração no código de produção - você tem alterações correspondentes no código de teste. O que é dor! Com os stubs, parece que você continua testando o comportamento, portanto, não são necessárias micro alterações no código de teste.
tucq88

35

Acho que a resposta mais simples e clara sobre essa questão é dada por Roy Osherove em seu livro A arte do teste de unidade (página 85)

A maneira mais fácil de dizer que estamos lidando com um esboço é perceber que o esboço nunca pode falhar no teste. As afirmações que o teste usa são sempre contra a classe em teste.

Por outro lado, o teste usará um objeto simulado para verificar se o teste falhou ou não. [...]

Novamente, o objeto simulado é o objeto que usamos para verificar se o teste falhou ou não.

Isso significa que, se você está fazendo afirmações contra o falso, significa que você está usando o falso como uma farsa; se você está usando o falso apenas para executar o teste sem afirmação, está usando o falso como um esboço.


2
Eu gostaria que sua resposta chegasse ao topo. Aqui está R. Osherove explicando isso youtu.be/fAb_OnooCsQ?t=1006 .
Michael Ekoka

31

Lendo todas as explicações acima, deixe-me tentar condensar:

  • Stub : um pedaço de código fictício que permite a execução do teste, mas você não se importa com o que acontece com ele.
  • Mock : um pedaço de código fictício que você VERIFY é chamado corretamente como parte do teste.
  • Spy : um trecho de código fictício que intercepta algumas chamadas para um trecho de código real, permitindo que você verifique as chamadas sem substituir o objeto original inteiro.

4
Boa resposta. Mock soa bastante semelhante ao Spy, com base em sua definição. Seria bom se você atualizou sua resposta para incluir mais algumas duplas de teste.
Rowan Gontier

Eu não tinha ouvido falar de Spy quando escrevi esta resposta.
O'Rooney

23

Um mock está apenas testando o comportamento, certificando-se de que certos métodos sejam chamados. Um Stub é uma versão testável (por si só) de um objeto específico.

O que você quer dizer com Apple?


19
"O que você quer dizer com Apple?" Use Helvetica
kubi

7
De forma a Apple em oposição ao de uma forma Microsoft :)
never_had_a_name

2
Isso ajuda a situação?
NebulaFox

21

Se você compará-lo à depuração:

O stub é como garantir que um método retorne o valor correto

Mock é como entrar no método e garantir que tudo esteja correto antes de retornar o valor correto.


20

O uso de um modelo mental realmente me ajudou a entender isso, e não todas as explicações e artigos, que não "afundaram".

Imagine que seu filho tem um prato de vidro na mesa e ele começa a brincar com ele. Agora, você tem medo que isso se quebre. Então, você dá a ele um prato de plástico. Isso seria uma simulação (mesmo comportamento, mesma interface, implementação "mais suave").

Agora, diga que você não tem o substituto de plástico e explique "Se continuar jogando, ele quebrará!". Esse é um esboço , você forneceu um estado predefinido com antecedência.

Um manequim seria o garfo que ele nem usava ... e um Spy poderia ser algo como fornecer a mesma explicação que você já usou e que funcionou.


19

Eu acho que a diferença mais importante entre eles são suas intenções.

Deixe-me tentar explicá-lo no porquê stub vs. WHY mock

Suponha que eu esteja escrevendo um código de teste para o controlador de linha do tempo público do meu cliente do twitter do mac

Aqui está o código de amostra de teste

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB: A conexão de rede à API do twitter é muito lenta, o que torna meu teste lento. Eu sei que ele retornará linhas de tempo, então fiz um esboço simulando a API do Twitter HTTP, para que meu teste o execute muito rapidamente e eu possa executar o teste mesmo estando offline.
  • MOCK: Ainda não escrevi nenhum dos meus métodos de interface do usuário e não tenho certeza de quais métodos preciso escrever para o meu objeto de interface do usuário. Espero saber como meu controlador colaborará com meu objeto de interface do usuário escrevendo o código de teste.

Ao escrever simulação, você descobre o relacionamento de colaboração dos objetos, verificando se as expectativas são atendidas, enquanto o stub simula apenas o comportamento do objeto.

Sugiro ler este artigo se você estiver tentando saber mais sobre zombarias: http://jmock.org/oopsla2004.pdf


1
Eu acho que você tem a idéia certa, mas Dillon Kearns explicou muito mais claramente.
O'Rooney

19

Para ser muito claro e prático:

Stub: Uma classe ou objeto que implementa os métodos da classe / objeto a ser falsificado e retorna sempre o que você deseja.

Exemplo em JavaScript:

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

Mock: O mesmo do stub, mas adiciona alguma lógica que "verifica" quando um método é chamado, assim você pode ter certeza de que alguma implementação está chamando esse método.

Como o @mLevan diz, imagine como exemplo que você está testando uma classe de registro de usuário. Depois de chamar Salvar, ele deve chamar SendConfirmationEmail.

Um código muito estúpido Exemplo:

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}

16

Este slide explica as principais diferenças muito boas.

insira a descrição da imagem aqui

* Da palestra CSE 403, 16, Universidade de Washington (slide criado por "Marty Stepp")


Esta é a explicação mais clara da diferença entre os dois, IMO. Para stub: o testador pega o Stub e o usa diretamente dentro da classe em teste. Mas, para o Mock, o testador precisa entender como o objeto Mock será usado. Em diferentes casos, ele se comportará de maneira diferente. Em contraste, esboço não é esperado para se comportar de forma diferente, mas é usado como ele é (ou seja, devolver os mesmos dados quando contactado)
Dexter

12

Gosto da explicação de Roy Osherove [link do vídeo] .

Toda classe ou objeto criado é falso. É uma zombaria se você verificar chamadas contra ela. Caso contrário, é um esboço.


12
  • Stubs vs. Mocks
    • Stubs
      1. fornecer respostas específicas para chamadas de métodos
        • ex: myStubbedService.getValues ​​() apenas retorna uma String necessária pelo código em teste
      2. usado pelo código em teste para isolá-lo
      3. não pode falhar no teste
        • ex: myStubbedService.getValues ​​() apenas retorna o valor stubbed
      4. geralmente implementa métodos abstratos
    • Zombaria
      1. "superconjunto" de stubs; pode afirmar que certos métodos são chamados
        • ex: verifique se myMockedService.getValues ​​() é chamado apenas uma vez
      2. usado para testar o comportamento do código em teste
      3. pode falhar no teste
        • ex: verifique se myMockedService.getValues ​​() foi chamado uma vez; a verificação falha, porque myMockedService.getValues ​​() não foi chamado pelo meu código testado
      4. zomba frequentemente de interfaces

11

vamos ver Duplas de teste:

  • Fake : Fakes são objetos que têm implementações de trabalho, mas não são iguais às de produção. Como : implementação na memória do Data Access Object ou Repository.
  • Stub : Stub é um objeto que contém dados predefinidos e os utiliza para atender chamadas durante os testes. Como : um objeto que precisa capturar alguns dados do banco de dados para responder a uma chamada de método.

  • Zombarias : zombarias são objetos que registram as chamadas que recebem. Na asserção de teste, podemos verificar no Mocks que todas as ações esperadas foram executadas. Como : uma funcionalidade que chama o serviço de envio de email. para mais, basta verificar isso .


1
melhor resposta na minha opinião
Ero Stefano

9

Uma farsa é um termo genérico que pode ser usado para descrever um esboço ou um objeto simulado (manuscrito ou não), porque ambos se parecem com o objeto real.

Se uma farsa é um esboço ou uma farsa depende de como é usada no teste atual. Se for usado para verificar uma interação (afirmada), é um objeto simulado. Caso contrário, é um esboço.

O Fakes garante que o teste seja executado sem problemas. Isso significa que o leitor do seu teste futuro entenderá qual será o comportamento do objeto falso, sem precisar ler seu código-fonte (sem precisar depender de recursos externos).

O que significa o teste executado sem problemas?
Exemplo no código abaixo:

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

Você deseja testar o método mailService.SendEMail () , para fazer isso, você precisa simular uma exceção no método de teste, portanto, basta criar uma classe errorService do Fake Stub para simular esse resultado, para que seu código de teste seja capaz de testar método mailService.SendEMail (). Como você vê, você precisa simular um resultado que é de outra classe External Dependency ErrorService.


8

Desde o artigo Mock Roles, e não Objects , pelos desenvolvedores do jMock:

Os stubs são implementações fictícias do código de produção que retornam resultados fixos. Objetos simulados agem como stubs, mas também incluem asserções para instrumentar as interações do objeto de destino com seus vizinhos.

Portanto, as principais diferenças são:

  • as expectativas definidas em stubs são geralmente genéricas, enquanto as expectativas definidas em zombarias podem ser mais "inteligentes" (por exemplo, retorne isso na primeira chamada, na segunda, etc.).
  • stubs são usados ​​principalmente para configurar entradas indiretas do SUT , enquanto zombarias podem ser usadas para testar entradas e saídas indiretas do SUT.

Em resumo, ao mesmo tempo em que tenta dispersar a confusão do título do artigo de Fowler : zombarias são stubs, mas não são apenas stubs .


1
Eu acho que você está certo, mas é por isso que o artigo de Fowler é confuso, o título do artigo é "Mocks Arn't Stubs" ... mas eles SÃO ?! # ¯_ (ツ) _ / ¯
stonedauwg

@stonedauwg, de fato, editei meu post para incorporar seu trocadilho e um esclarecimento. Espero que isso ajude um pouco mais.
Dimos

@stonedauwg, um mock não é um esboço, assim como um retângulo não é um quadrado. :)
seanriordan08

7

Eu estava lendo A arte do teste de unidade e me deparei com a seguinte definição:

Um falso é um termo genérico que pode ser usado para descrever um esboço ou um objeto falso (manuscrito ou não), porque ambos se parecem com o objeto real. Se uma farsa é um esboço ou uma farsa depende de como é usada no teste atual. se for usado para verificar uma interação (afirmada), é um objeto simulado . Caso contrário, é um esboço .


5

Me deparei com este artigo interessante do UncleBob The Little Mocker . Ele explica toda a terminologia de uma maneira muito fácil de entender, por isso é útil para iniciantes. O artigo de Martin Fowlers é uma leitura difícil, especialmente para iniciantes como eu.


4

O Stub nos ajuda a executar o teste. Quão? Fornece valores que ajudam a executar o teste. Esses valores não são reais e criamos esses valores apenas para executar o teste. Por exemplo, criamos um HashMap para fornecer valores semelhantes aos valores na tabela do banco de dados. Então, em vez de interagir diretamente com o banco de dados, interagimos com o Hashmap.

Mock é um objeto falso que executa o teste. onde colocamos afirmar.


"Então, em vez de interagir diretamente com o banco de dados, interagimos com o Hashmap." ... porque ainda não tivemos tempo de codificar o módulo de banco de dados e não pudemos executar o código de teste sem usar o stub. Caso contrário, o mesmo Hasmap seria uma farsa! direita?
Boris Däppen

4

Veja abaixo o exemplo de zombarias versus stubs usando a estrutura C # e Moq. Moq não tem uma palavra-chave especial para Stub, mas você pode usar o objeto Mock para criar stubs também.

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}

4

Ponto de vista de teste de Stub e Mock:

  • O Stub é uma implementação fictícia feita pelo usuário de maneira estática , ou seja, no Stub escrevendo o código de implementação. Portanto, ele não pode lidar com a definição de serviço e a condição dinâmica. Normalmente, isso é feito na estrutura JUnit sem usar a estrutura de simulação.

  • Mock também é uma implementação fictícia, mas sua implementação foi feita de maneira dinâmica usando estruturas de Mocking como o Mockito. Assim, podemos lidar com a definição de condição e serviço de maneira dinâmica, ou seja, simulações podem ser criadas dinamicamente a partir do código em tempo de execução. Portanto, usando o mock, podemos implementar Stubs dinamicamente.


3

Além de respostas úteis, um dos pontos mais poderosos do uso de Mocks do que Subs

Se o colaborador [do qual o código principal depende] não estiver sob nosso controle (por exemplo, de uma biblioteca de terceiros),
nesse caso, o stub é mais difícil de escrever do que simulado .


2

Eu usei exemplos de python na minha resposta para ilustrar as diferenças.

Stub - Stubbing é uma técnica de desenvolvimento de software usada para implementar métodos de classes no início do ciclo de vida do desenvolvimento. Eles são usados ​​normalmente como espaços reservados para a implementação de uma interface conhecida, onde a interface é finalizada ou conhecida, mas a implementação ainda não é conhecida ou finalizada. Você começa com stubs, o que significa simplesmente que você apenas escreve a definição de uma função e deixa o código real para mais tarde. A vantagem é que você não esquecerá os métodos e poderá continuar pensando no seu design enquanto o vê no código. Você também pode fazer com que seu stub retorne uma resposta estática para que a resposta possa ser usada por outras partes do seu código imediatamente. Os objetos Stub fornecem uma resposta válida, mas é estática, não importa qual entrada você passe, você sempre terá a mesma resposta:

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

Objetos simulados são usados ​​em casos de teste simulados e validam que certos métodos são chamados nesses objetos. Objetos simulados são objetos simulados que imitam o comportamento de objetos reais de maneira controlada. Você normalmente cria um objeto simulado para testar o comportamento de outro objeto. As zombarias permitem simular recursos indisponíveis ou muito pesados ​​para testes de unidade.

mymodule.py:

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py:

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

Este é um exemplo muito básico que apenas executa rm e afirma o parâmetro com o qual foi chamado. Você pode usar simulação com objetos, não apenas funções, como mostrado aqui, e também pode retornar um valor para que um objeto falso possa ser usado para substituir um stub para teste.

Mais sobre o unittest.mock , observe que o python 2.x mock não está incluído no unittest, mas é um módulo para download que pode ser baixado via pip (pip install mock).

Também li "The Art of Unit Testing", de Roy Osherove, e acho que seria ótimo se um livro semelhante fosse escrito usando exemplos de Python e Python. Se alguém souber desse livro, compartilhe. Felicidades :)


2

Um stub é um objeto falso criado para fins de teste. Um mock é um esboço que registra se as chamadas esperadas ocorreram efetivamente.


2

Um stub é uma função vazia que é usada para evitar exceções não tratadas durante os testes:

function foo(){}

Uma simulação é uma função artificial usada para evitar dependências de SO, ambiente ou hardware durante os testes:

function foo(bar){ window = this; return window.toString(bar); }

Em termos de afirmações e estado:

  • Zombarias são declaradas antes de um evento ou mudança de estado
  • Os stubs não são declarados, eles fornecem um estado antes de um evento para evitar a execução de código de unidades não relacionadas
  • Os espiões são configurados como stubs, depois declarados após uma alteração de evento ou estado
  • As falsificações não são declaradas, elas são executadas após um evento com dependências codificadas para evitar o estado

Referências


2
+1 para adicionar espiões ao glossário. Além disso, eu acho que você quer dizer "Spies são configurados como simulações" não "Spies são configurados como topos"
Sameh Deabes


2

Um mock é um objeto técnico e funcional .

A zombaria é técnica . É de fato criado por uma biblioteca de simulação (EasyMock, JMockit e mais recentemente Mockito são conhecidos por isso) graças à geração de código de bytes .
A implementação simulada é gerada de uma maneira em que poderíamos instrumentá- la para retornar um valor específico quando um método é chamado, mas também algumas outras coisas, como verificar se um método simulado foi chamado com alguns parâmetros específicos (verificação estrita) ou quaisquer que sejam os parâmetros ( nenhuma verificação rigorosa).

Instanciando uma simulação:

@Mock Foo fooMock

Gravando um comportamento:

when(fooMock.hello()).thenReturn("hello you!");

Verificando uma chamada:

verify(fooMock).hello()

Claramente, essa não é a maneira natural de instanciar / substituir a classe / comportamento Foo. Por isso me refiro a um aspecto técnico.

Mas o mock também é funcional porque é uma instância da classe que precisamos isolar do SUT. E com comportamentos registrados, poderíamos usá-lo no SUT da mesma maneira que faria com um esboço.


O stub é apenas um objeto funcional : é uma instância da classe que precisamos isolar do SUT e isso é tudo. Isso significa que a classe de stub e todos os acessórios de comportamento necessários durante nossos testes de unidade devem ser definidos explicitamente.
Por exemplo, o stub hello()precisaria subclassificar a Fooclasse (ou implementar sua interface) e substituir hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

Se outro cenário de teste exigir outro retorno de valor, provavelmente precisaremos definir uma maneira genérica de definir o retorno:

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

Outro cenário: se eu tivesse um método de efeito colateral (sem retorno) e verificasse se esse método foi chamado, provavelmente deveria ter adicionado um booleano ou um contador na classe de stub para contar quantas vezes o método foi chamado.


Conclusão

Geralmente, o stub exige muita sobrecarga / código para escrever no seu teste de unidade. Que simulação evita graças ao fornecimento de recursos de gravação / verificação prontos para uso.
É por isso que hoje em dia, a abordagem de stub raramente é usada na prática com o advento de excelentes bibliotecas simuladas.


Sobre o artigo de Martin Fowler: Não acho que seja um programador "zombeteiro" enquanto uso zombarias e evito stubs.
Mas eu uso o mock quando é realmente necessário (dependências irritantes) e sou a favor dos testes de fatia e miniintegração quando testo uma classe com dependências cujo mock seria uma sobrecarga.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.