Eu tenho algum tipo de dados de teste e quero criar um teste de unidade para cada item. Minha primeira ideia foi fazer assim:
import unittest
l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]
class TestSequence(unittest.TestCase):
def testsample(self):
for name, a,b in l:
print "test", name
self.assertEqual(a,b)
if __name__ == '__main__':
unittest.main()
A desvantagem disso é que ele lida com todos os dados em um teste. Gostaria de gerar um teste para cada item em tempo real. Alguma sugestão?
python
unit-testing
parameterized-unit-test
Peter Hoffmann
fonte
fonte
Respostas:
Isso é chamado de "parametrização".
Existem várias ferramentas que suportam essa abordagem. Por exemplo:
O código resultante é assim:
O que gerará os testes:
Por razões históricas, deixarei a resposta original por volta de 2008):
Eu uso algo como isto:
fonte
.__name__ =
habilitar o.exact_method
testeif __name__ == '__main__'
condicional? Certamente ele deve ir fora desta para executar em tempo de importação (lembrando que módulos python, apenas são importados, uma vez, mesmo se importado de vários lugares diferentes)Usando unittest (desde 3.4)
Desde o Python 3.4, o
unittest
pacote de biblioteca padrão possui osubTest
gerenciador de contexto.Veja a documentação:
Exemplo:
Você também pode especificar uma mensagem personalizada e valores de parâmetro para
subTest()
:Usando nariz
A estrutura de teste do nariz suporta isso .
Exemplo (o código abaixo é todo o conteúdo do arquivo que contém o teste):
A saída do comando nosetests:
fonte
Isso pode ser resolvido com elegância usando Metaclasses:
fonte
__new__
método na metaclasse é chamado quando a própria classe é definida, não quando a primeira instância é criada. Eu imagino que esse método de criação dinâmica de métodos de teste seja mais compatível com a introspecção usadaunittest
para determinar quantos testes há em uma classe (ou seja, ele pode compilar a lista de testes antes de criar uma instância dessa classe).class TestSequence(unittest.TestCase, metaclass=TestSequenceMeta):[...]
dct
vez dedict
? Usar palavras-chave como nomes de variáveis é confuso e propenso a erros.A partir do Python 3.4, os subtestes foram introduzidos como unittest para esse fim. Veja a documentação para detalhes. TestCase.subTest é um gerenciador de contexto que permite isolar afirmações em um teste para que uma falha seja relatada com informações de parâmetro, mas não interrompa a execução do teste. Aqui está o exemplo da documentação:
A saída de uma execução de teste seria:
Isso também faz parte do unittest2 , portanto está disponível para versões anteriores do Python.
fonte
setUp()
etearDown()
não são executados entre os sub-testes.)self.setUp()
em teoria pode ser chamado manualmente a partir do subteste. Quanto atearDown
, tê-lo chamado automaticamente no final pode ser suficiente.load_tests é um mecanismo pouco conhecido introduzido no 2.7 para criar dinamicamente um TestSuite. Com ele, você pode criar facilmente testes parametrizados.
Por exemplo:
Esse código executará todos os TestCases no TestSuite retornados por load_tests. Nenhum outro teste é executado automaticamente pelo mecanismo de descoberta.
Como alternativa, você também pode usar a herança como mostrado neste ticket: http://bugs.python.org/msg151444
fonte
Isso pode ser feito usando pytest . Basta escrever o arquivo
test_me.py
com o conteúdo:E executar o teste com o comando
py.test --tb=short test_me.py
. Em seguida, a saída será semelhante a:É simples! Também pytest tem mais recursos, como
fixtures
,mark
,assert
, etc ...fonte
py.test
unittest
para py.test. Eu costumava terTestCase
classes base que eram capazes de criar dinamicamente crianças com argumentos diferentes que eles armazenavam como variáveis de classe ... o que era um pouco pesado.py.test
é yield_fixtures . O que pode fazer a configuração , retornar alguns dados úteis para o teste e, após o término do teste, desmontar . As luminárias também podem ser parametrizadas .Use a biblioteca ddt . Ele adiciona decoradores simples para os métodos de teste:
Esta biblioteca pode ser instalada com
pip
. Não requernose
e funciona excelente com ounittest
módulo de biblioteca padrão .fonte
Você se beneficiaria de experimentar a biblioteca TestScenarios .
fonte
Há também a hipótese que adiciona testes baseados em propriedades ou fuzz: https://pypi.python.org/pypi/hypothesis
Este é um método de teste muito poderoso.
fonte
@given()
macro dentro da classe mais unittest.Você pode usar o plugin nose-ittr (
pip install nose-ittr
).É muito fácil integrar-se aos testes existentes, são necessárias alterações mínimas (se houver). Ele também suporta plug-in de multiprocessamento do nariz .
Não que você também possa ter uma
setup
função de customização por teste.Também é possível passar
nosetest
parâmetros como com seu plug-in embutidoattrib
; dessa forma, você pode executar apenas um teste específico com um parâmetro específico:fonte
Uso metaclasses e decoradores para gerar testes. Você pode verificar minha implementação python_wrap_cases . Esta biblioteca não requer nenhuma estrutura de teste.
Seu exemplo:
Saída do console:
Além disso, você pode usar geradores . Por exemplo, esse código gera todas as combinações possíveis de testes com argumentos
a__list
eb__list
Saída do console:
fonte
Me deparei com o ParamUnittest outro dia, quando olhamos o código fonte para o radônio ( exemplo de uso no repositório do github ). Ele deve funcionar com outras estruturas que estendem o TestCase (como o Nariz).
Aqui está um exemplo:
fonte
RESULTADO:
fonte
def add_test_methods
função. Deve serdef _add_test_methods
eu pensoBasta usar metaclasses, como visto aqui;
Resultado:
fonte
Você pode usar
TestSuite
e customizarTestCase
classes.fonte
__init__
função.Eu descobri que isso funciona bem para meus propósitos, especialmente se eu precisar gerar testes que diferenciem ligeiramente os processos em uma coleta de dados.
A
TestGenerator
classe pode ser usada para gerar diferentes conjuntos de casos de teste, comoTestCluster
.TestCluster
pode ser pensado como uma implementação daTestGenerator
interface.fonte
Esta solução funciona com
unittest
enose
para Python 2 e Python 3:fonte
Eu estava tendo problemas com um estilo muito particular de testes parametrizados. Todos os nossos testes do Selenium podem ser executados localmente, mas também devem ser executados remotamente em várias plataformas no SauceLabs. Basicamente, eu queria pegar uma grande quantidade de casos de teste já escritos e parametrizá-los com o menor número possível de alterações no código. Além disso, eu precisava ser capaz de passar os parâmetros para o método setUp, algo que não vi soluções para outro lugar.
Aqui está o que eu vim com:
Com isso, tudo que eu precisava fazer era adicionar um decorador simples @sauce_labs () a cada TestCase antigo e agora, quando executá-los, eles são embrulhados e reescritos, para que todos os métodos de teste sejam parametrizados e renomeados. LoginTests.test_login (self) é executado como LoginTests.test_login_internet_explorer_10.0 (self), LoginTests.test_login_internet_explorer_11.0 (self) e LoginTests.test_login_firefox_43.0 (self) e cada um tem o parâmetro self.platform para decidir qual navegador / plataforma a ser executada, mesmo no LoginTests.setUp, que é crucial para a minha tarefa, pois é aí que a conexão com o SauceLabs é inicializada.
De qualquer forma, espero que isso ajude alguém que deseja fazer uma parametrização "global" semelhante de seus testes!
fonte
As respostas baseadas em metaclasse ainda funcionam no Python3, mas, em vez do
__metaclass__
atributo, é necessário usar ometaclass
parâmetro, como em:fonte
A metaprogramação é divertida, mas pode continuar. A maioria das soluções aqui dificulta:
Portanto, minha primeira sugestão é seguir o caminho simples / explícito (funciona com qualquer executor de teste):
Como não devemos nos repetir, minha segunda sugestão baseia-se na resposta de @ Javier: adotar testes baseados em propriedades. Biblioteca de hipóteses:
possui muitos recursos mais interessantes (estatísticas, resultados adicionais de testes, ...)
classe TestSequence (unittest.TestCase):
Para testar seus exemplos específicos, basta adicionar:
Para executar apenas um exemplo em particular, você pode comentar os outros exemplos (o exemplo fornecido será executado primeiro). Você pode querer usar
@given(st.nothing())
. Outra opção é substituir o bloco inteiro por:Ok, você não tem nomes de teste distintos. Mas talvez você só precise:
Exemplo mais engraçado
fonte
Tarde demais para a festa, mas tive problemas para fazer isso funcionar
setUpClass
.Aqui está uma versão da resposta de @ Javier que dá
setUpClass
acesso a atributos alocados dinamicamente.Saídas
fonte
Apenas para jogar outra solução na mistura;)
É efetivamente o mesmo que
parameterized
o mencionado acima, mas específico paraunittest
:Exemplo de uso:
fonte
Além de usar o setattr, podemos usar load_tests desde o python 3.2. Consulte a postagem do blog blog.livreuro.com/en/coding/python/how-to-generate-discoverable-unit-tests-in-python-dynamically/
fonte
A seguir está a minha solução. Acho isso útil quando: 1. Deve funcionar para unittest.Testcase e unittest discover 2. Tenha um conjunto de testes a serem executados para diferentes configurações de parâmetros. 3. Muito simples, sem dependência de outros pacotes importam unittest
fonte
fonte