Pular para o conteúdo

Como usar o unittest mock?

[

Entendendo a Biblioteca de Objetos Mock no Python

por Alex Ronquillo

O que é o Mocking?

Um objeto mock substitui e imita um objeto real dentro de um ambiente de teste. É uma ferramenta versátil e poderosa para melhorar a qualidade dos seus testes.

Uma razão para usar objetos Mock no Python é controlar o comportamento do seu código durante os testes. Por exemplo, se o seu código faz requisições HTTP para serviços externos, seus testes funcionam de forma previsível apenas até o ponto que esses serviços se comportam como esperado. Às vezes, uma mudança temporária no comportamento desses serviços externos pode causar falhas intermitentes em seu conjunto de testes.

Por isso, é melhor testar seu código em um ambiente controlado. Substituir a requisição real por um objeto mock permitiria simular falhas de serviço externo e respostas bem-sucedidas de uma maneira previsível.

Às vezes, é difícil testar áreas específicas do seu código. Essas áreas incluem blocos except e declarações if que são difíceis de satisfazer. Usar objetos mock no Python pode ajudar a controlar o caminho de execução do seu código para alcançar essas áreas e melhorar a cobertura do código.

A Biblioteca de Objetos Mock do Python

O Python possui uma biblioteca chamada unittest.mock que oferece várias funcionalidades para criar objetos mock e executar testes mais eficientes. A seguir, veremos os principais recursos dessa biblioteca.

O Objeto Mock

O objeto Mock é a base da biblioteca unittest.mock e permite criar mocks personalizados para uso nos testes. Ele possui atributos e métodos que podem ser configurados de acordo com as necessidades do teste.

Atributos e Métodos Lazy

Os objetos Mock permitem a criação de atributos e métodos preguiçosos, ou seja, eles só serão criados quando forem acessados pela primeira vez. Isso é útil quando você deseja simular um comportamento específico apenas em determinadas situações do teste.

Veja um exemplo de criação de um objeto Mock com um atributo preguiçoso:

from unittest.mock import Mock
obj = Mock()
obj.attribute.lazy_attribute

Asserções e Inspeções

Os objetos Mock possuem métodos de asserção que podem ser usados para verificar se o objeto foi usado da maneira esperada durante o teste. Além disso, é possível inspecionar os dados de uso armazenados no objeto Mock.

Veja um exemplo de como utilizar asserções e inspeções em um objeto Mock:

from unittest.mock import Mock
obj = Mock()
obj.method(1, 2)
obj.method.assert_called_once_with(1, 2)
assert obj.method.call_count == 1

Gerenciando o Valor de Retorno de um Mock

É possível configurar o valor de retorno de um objeto Mock para simular diferentes cenários de teste. Isso permite controlar a lógica do código e testar casos específicos facilmente.

Veja um exemplo de como configurar o valor de retorno de um objeto Mock:

from unittest.mock import Mock
obj = Mock()
obj.method.return_value = 42
result = obj.method()
assert result == 42

Gerenciando os Efeitos Colaterais de um Mock

Além de retornar um valor específico, os objetos Mock podem ser configurados para realizar efeitos colaterais, como lançar uma exceção ou modificar um atributo durante a chamada de um método. Isso é útil quando você deseja testar como o código se comporta em situações de falha.

Veja um exemplo de como gerenciar os efeitos colaterais de um objeto Mock:

from unittest.mock import Mock
obj = Mock()
obj.method.side_effect = Exception("Something went wrong")
try:
obj.method()
except Exception as e:
assert str(e) == "Something went wrong"

Configurando seu Mock

Além das funcionalidades mencionadas acima, os objetos Mock oferecem diversas opções de configuração, como modificar o nome do objeto, criar mocks filhos e muito mais. Essas opções permitem personalizar o comportamento do objeto Mock de acordo com as necessidades do teste.

A Função patch()

A função patch() é uma das funcionalidades mais poderosas da biblioteca unittest.mock. Ela permite substituir um objeto real por um objeto mock em um determinado contexto.

A função patch() pode ser usada como um decorador ou como um gerenciador de contexto. Ela pode substituir os atributos de um objeto real por mocks ou até mesmo patchear um módulo inteiro.

Veja alguns exemplos de como utilizar a função patch():

from unittest.mock import patch
@patch("my_module.my_function")
def test_mocked_function(mock_function):
# Test the function with the mocked version
...
with patch("my_module.my_class") as mock_class:
# Test code that uses the mocked class
...

Problemas Comuns no Mocking

O uso de objetos Mock no Python pode trazer alguns desafios específicos. Alguns problemas comuns incluem mudanças nas interfaces de objetos e dependências externas.

É importante estar ciente desses problemas ao utilizar objetos Mock em seus testes e adotar práticas para evitá-los.

Evitando Problemas Comuns com Especificações

Uma maneira de evitar problemas comuns ao utilizar objetos Mock é utilizar especificações. As especificações definem restrições para o objeto mock em relação às suas classes ou interfaces reais correspondentes, evitando assim mudanças inesperadas ou erros de digitação.

Utilizar especificações pode tornar seus testes mais robustos e garantir que o objeto mock se comporte como o objeto real esperado.

Conclusão

A biblioteca de objetos Mock no Python, unittest.mock, é uma ferramenta poderosa para melhorar a qualidade dos seus testes. Ela permite criar objetos mock personalizados, substituir objetos reais por mocks durante os testes e evita problemas comuns associados ao uso de mocks.

Ao entender e dominar as funcionalidades da biblioteca de objetos Mock, você poderá escrever testes mais eficientes e confiáveis para o seu código Python.

Experimente você mesmo!

Agora que você aprendeu sobre a biblioteca de objetos Mock no Python, experimente utilizar os conceitos apresentados para escrever testes mais robustos para o seu código. Lembre-se de explorar todas as funcionalidades da biblioteca e adaptá-las às suas necessidades específicas.

Happy coding!