Pergunta

Eu tenho um arquivo de teste que contém testes que tomam bastante tempo (eles enviam cálculos para um cluster e espera para o resultado). Todos estes são na classe TestCase específico.

Uma vez que eles levam tempo e, além disso, não são propensos a quebrar, eu gostaria de ser capaz de escolher se este subconjunto de testes faz ou não executar (a melhor maneira seria com um argumento de linha de comando, ou seja " ./tests.py --offline" ou algo parecido), para que eu pudesse executar a maioria dos testes de frequência e de forma rápida e todo o conjunto de vez em quando, quando eu tiver tempo.

Por enquanto, eu só uso unittest.main() para iniciar os testes.

Graças.

Foi útil?

Solução

O unittest.main() padrão usa o carregador de teste padrão para fazer um TestSuite fora do módulo no qual principal está em execução.

Você não tem que usar esse comportamento padrão.

Você pode, por exemplo, fazer três casos unittest.TestSuite .

  1. O "rápido" subconjunto.

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. O "lento" subconjunto.

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. O "todo" set.

    alltests = unittest.TestSuite([fast, slow])
    

Note que eu já ajustou os nomes testcase para indicar rápido contra lento. Você pode subclasse unittest.TestLoader para analisar os nomes de classes e criar vários carregadores.

Em seguida, o programa principal pode analisar argumentos de linha de comando com optparse ou argparse (disponível desde 2.7 ou 3.2) para escolher qual conjunto você deseja executar, rápido, lento ou todos.

Ou, você pode confiar que sys.argv[1] é um dos três valores e usar algo tão simples como isto

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

Outras dicas

Para executar apenas um único teste específico você pode usar:

$ python -m unittest test_module.TestClass.test_method

Mais informações aqui

Na verdade, pode-se passar os nomes do caso de teste como sys.argv e apenas os casos serão testados.

Por exemplo, suponha que você tenha

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

Você pode chamar

python test.py account
única

para ter em conta os testes, ou mesmo

$ python test.py account customer

para ter ambos os casos testados

Estou fazendo isso usando um skipIf simples:

import os

SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0'))

@unittest.skipIf(not SLOW_TESTS, "slow")
class CheckMyFeature(unittest.TestCase):
    def runTest(self):
        …

Desta forma, eu só precisa decorar um caso de teste já existente com esta linha única (não há necessidade de criar suites de teste ou semelhante, assim que a linha chamada um os.getenv() no início do meu arquivo de teste de unidade), e como um padrão este teste fica ignorado.

Se eu quiser para executá-lo, apesar de ser lento, eu apenas chamar meu script assim:

SLOW_TESTS=1 python -m unittest …

Você tem basicamente duas maneiras de fazer isso:

  1. Defina o seu próprio conjunto de testes para a classe
  2. Criar classes de simulação da conexão cluster que irá retornar dados reais.

Eu sou um forte defensor de que ele segunda abordagem; um teste de unidade deve teste apenas uma unidade de código, e não sistemas complexos (como bancos de dados ou clusters). Mas eu entendo que nem sempre é possível; às vezes, criando maquetes é simplesmente demasiado caro, ou o objetivo do teste é realmente no sistema complexo.

Voltar a opção (1), você pode proceder da seguinte maneira:

suite = unittest.TestSuite()
suite.addTest(MyUnitTestClass('quickRunningTest'))
suite.addTest(MyUnitTestClass('otherTest'))

e, em seguida, passar a suite para o corredor de teste:

unittest.TextTestRunner().run(suite)

Mais informações sobre a documentação python: http://docs.python.org /library/unittest.html#testsuite-objects

Uma vez que você usa unittest.main() você pode simplesmente executar python tests.py --help para obter a documentação:

Usage: tests.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
  tests.py                               - run default set of tests
  tests.py MyTestSuite                   - run suite 'MyTestSuite'
  tests.py MyTestCase.testSomething      - run MyTestCase.testSomething
  tests.py MyTestCase                    - run all 'test*' test methods
                                               in MyTestCase

Isto é, você pode simplesmente fazer

python tests.py TestClass.test_method

Ou você pode fazer uso da função unittest.SkipTest(). Exemplo, adicionar um método skipOrRunTest à sua classe de teste como este:

def skipOrRunTest(self,testType):
    #testsToRun = 'ALL'
    #testsToRun = 'testType1, testType2, testType3, testType4,...etc'
    #testsToRun = 'testType1'
    #testsToRun = 'testType2'
    #testsToRun = 'testType3'
    testsToRun = 'testType4'              
    if ((testsToRun == 'ALL') or (testType in testsToRun)):
        return True 
    else:
        print "SKIPPED TEST because:\n\t testSuite '" + testType  + "' NOT IN testsToRun['" + testsToRun + "']" 
        self.skipTest("skipppy!!!")

Em seguida, adicione uma chamada para este método skipOrRunTest para o início de cada um dos seus testes de unidade como esta:

def testType4(self):
    self.skipOrRunTest('testType4')

Eu encontrei outra solução, com base em como o decorador unittest.skip funciona. Ao definir o __unittest_skip__ e __unittest_skip_why__.

baseado em rótulo

Eu queria aplicar um sistema de rotulagem, para rotular alguns testes como quick, slow, glacier, memoryhog, cpuhog, core, e assim por diante.

all 'quick' tests Em seguida, executar, ou run everything except 'memoryhog' tests, sua lista branca básica / setup lista negra

Implementação

Eu implementei este em 2 partes:

  1. Primeiro adicione rótulos para testes (via um decorador costume classe @testlabel)
  2. unittest.TestRunner personalizado para identificar quais testes para saltar, e modificar o conteúdo testlist antes de executar.

implementação de Trabalho é neste essência: https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(a exemplo totalmente funcional era demasiado longo para colocar aqui)

O ser resultado ...

$ ./runtests.py --blacklist foo
test_foo (test_things.MyTest2) ... ok
test_bar (test_things.MyTest3) ... ok
test_one (test_things.MyTests1) ... skipped 'label exclusion'
test_two (test_things.MyTests1) ... skipped 'label exclusion'

----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK (skipped=2)

Todos os testes de classe MyTests1 são ignorados porque tem o rótulo foo.

--whitelist também funciona

olhar para usar um TestRunner dedicado, como py.test, nariz ou possivelmente até mesmo zope.testing. Todos eles têm opções de linha de comando para seleção de testes.

Olhe por exemplo, como Nariz: https://pypi.python.org/pypi /nose/1.3.0

Eu tentei resposta da @ slott:

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

Mas isso me deu o seguinte erro:

Traceback (most recent call last):
  File "functional_tests.py", line 178, in <module>
    unittest.TextTestRunner().run(suite)
  File "/usr/lib/python2.7/unittest/runner.py", line 151, in run
    test(result)
  File "/usr/lib/python2.7/unittest/case.py", line 188, in __init__
    testMethod = getattr(self, methodName)
TypeError: getattr(): attribute name must be string

A seguir trabalhou para mim:

if __name__ == "__main__":
    test_class = eval(sys.argv[1])
    suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
    unittest.TextTestRunner().run(suite)

Eu encontrei outra maneira de selecionar o test_ * métodos que eu só quero correr, adicionando um atributo para eles. Você basicamente usar um metaclass para decorar as funções chamáveis ??dentro da classe TestCase que tem o atributo StepDebug com um decorador unittest.skip. Mais informações sobre

Skipping todos os testes de unidade, mas uma em Python usando decoradores e metaclasses

Eu não sei se é uma solução melhor do que aqueles acima estou apenas fornecendo-lo como uma opção.

não encontrei uma boa maneira de fazer isso antes, assim, compartilhar aqui.

Objetivo: Obter um conjunto de arquivos de teste em conjunto para que eles possam ser executados como uma unidade, mas ainda pode selecionar qualquer um deles para executar por si só.

Problema:. A descobrir método não permite a seleção fácil de um único caso de teste para executar

Desenho: veja abaixo. Este achata do namespace assim pode selecionar pelo nome da classe TestCase, e deixar de fora o prefixo "tests1.test_core":

./run-tests TestCore.test_fmap

Código

  test_module_names = [
    'tests1.test_core',
    'tests2.test_other',
    'tests3.test_foo',
    ]

  loader = unittest.defaultTestLoader
  if args:
    alltests = unittest.TestSuite()
    for a in args:
      for m in test_module_names:
        try:
          alltests.addTest( loader.loadTestsFromName( m+'.'+a ) )
        except AttributeError as e:
          continue
  else:
    alltests = loader.loadTestsFromNames( test_module_names )

  runner = unittest.TextTestRunner( verbosity = opt.verbose )
  runner.run( alltests )

Esta é a única coisa que funcionou para mim.

if __name__ == '__main__':
unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

Quando liguei para ele que eu tinha que passar o nome do nome da classe e testar. Um pouco inconveniente desde que eu não tenho classe e nome do teste combinação memorizada.

python ./tests.py class_Name.test_30311

A remoção do nome da classe e nome do teste é executado todos os testes em seu arquivo. Acho isso muito mais fácil lidar com o então construído no método desde que eu realmente não mudar o meu comando no CLI. Basta adicionar o parâmetro.

Aproveite, Keith

Eu criei um decorador que permite a marcação testes como testes lentos e ignorá-los usando uma variável de ambiente

from unittest import skip
import os

def slow_test(func):
    return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func)

Agora você pode marcar seus testes tão lento como este:

@slow_test
def test_my_funky_thing():
    perform_test()

E pular testes lentas, definindo a variável de ambiente SKIP_SLOW_TESTS:

SKIP_SLOW_TESTS=1 python -m unittest
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top