Ultimamente, tive que escrever testes de unidade usando Pytest para um módulo Python. O módulo contém uma classe onde outras classes são inicializadas dentro de seu construtor.
Como sempre, criei um acessório para esta classe para facilitar a escrita de um teste para cada método de classe. Neste ponto, encontrei alguns problemas ao tentar zombar das diferentes classes iniciadas no construtor. A simulação não funcionou e instâncias dessas classes ainda estavam sendo criadas.
Depois de pesquisar e combinar algumas soluções diferentes que encontrei online, quero compartilhar como consegui simular as aulas.
Aqui está um exemplo da classe que tentei simular:
class ClassA: def __init__(self): self.class_b = ClassB() self.class_c = ClassC() self.count = 0
Queremos definir um valor para cada campo desta classe durante os testes. Este valor pode ser None ou uma simulação de classe, mas não queremos iniciações das classes ClassB e ClassC.
No nosso caso, vamos decidir que self.class_b e self.class_c devem ser simulações:
@pytest.fixture def mock_class_b(): class_b = Mock(spec=ClassB) return class_b @pytest.fixture def mock_class_c(): class_c = Mock(spec=ClassC) return class_c
Portanto, um acessório para esta classe que atenda ao nosso objetivo é assim:
@pytest.fixture def class_a_mock(mock_class_b, mock_class_c): with patch.object(target=ClassA, attribute="__init__", return_value=None) as mock_init: class_a = ClassA() class_a.class_b = mock_class_b class_a.class_c = mock_class_c class_b.count = 0 return class_a
A parte importante é como usar a função patch.object, que vem do módulo unittest.mock em Python. É usado em testes para substituir temporariamente um atributo de um determinado objeto por uma simulação ou outro valor.
Argumentos
Desta forma podemos criar variáveis simuladas em nosso fixture.
Leia mais sobre patch.object
Escrevi este tutorial para este tipo de casos em que, por qualquer motivo, não podemos alterar o código da Classe A. No entanto, geralmente recomendo modificar o código se possível, não para alterar a lógica, mas para torná-lo mais testável .
Aqui estão alguns exemplos de como modificar a Classe A para torná-la mais testável:
Opção 1: Passe instâncias da classe B e da classe C como parâmetros.
Dessa forma, quando escrevemos o fixture, podemos passar mocks em vez de instâncias.
class ClassA: def __init__(self, class_b_instance, class_c_instance): self.class_b = class_b_instance self.class_c = class_c_instance self.count = 0
Opção 2: Crie uma variável booleana que indique o modo de teste.
Desta forma podemos decidir quais campos da classe A receberão ou não um valor quando for iniciado.
class ClassA: def __init__(self, test_mode=False): if not test_mode: self.class_b = ClassB() self.class_c = ClassC() self.count = 0
Opção 3: Faça iniciações de aula em um método separado.
Essa abordagem nos dá a opção de evitar chamar set_class_variables no módulo de teste.
class ClassA: def __init__(self): self.class_b = None self.class_c = None self.count = None def set_class_variables(self): self.class_b = ClassB() self.class_c = ClassC() self.count = 0
Espero que isso ajude! :)
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3