"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Zombando de classes Python

Zombando de classes Python

Publicado em 2024-11-03
Navegar:130

Mocking Python Classes

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.

Solução

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

  1. target=ClassA: o objeto (geralmente uma classe) cujo atributo queremos corrigir.
  2. attribute="__init__": o nome do atributo que queremos corrigir.
  3. return_value=None: substituindo o método __init__ por uma função que não faz nada

Desta forma podemos criar variáveis ​​simuladas em nosso fixture.
Leia mais sobre patch.object

Dicas de teste

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! :)

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/chen_ashkenazi/mocking-python-classes-4h96?1 Se houver alguma violação, entre em contato com [email protected] para excluí-la
Tutorial mais recente Mais>

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