Domanda

Ho un file di test che contiene i test che prendono un bel po 'di tempo (mandano i calcoli a un cluster e attendere il risultato). Tutti questi sono in specifica classe di TestCase.

Dal momento che richiedono tempo e, inoltre, non sono suscettibili di rompersi, avrei voluto essere in grado di scegliere se questo sottoinsieme di test fa o non funziona (il modo migliore sarebbe con un argomento della riga di comando, vale a dire " ./tests.py --offline" o qualcosa di simile), così ho potuto eseguire la maggior parte dei test, spesso e rapidamente e l'intero set di tanto in tanto, quando ho tempo.

Per il momento, mi basta usare unittest.main() per iniziare i test.

Grazie.

È stato utile?

Soluzione

Il predefinito unittest.main() utilizza il caricatore test di default per effettuare una TestSuite dal modulo principale in cui è in esecuzione.

Non è necessario utilizzare questo comportamento predefinito.

È possibile, ad esempio, fare tre unittest.TestSuite casi .

  1. Il sottoinsieme "veloce".

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. Il "lento" sottoinsieme.

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. L ' "intero" set.

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

Si noti che Ho modificato i nomi TestCase per indicare veloci o lente. È possibile creare una sottoclasse unittest.TestLoader per analizzare i nomi delle classi e creare più caricatori.

Poi il programma principale in grado di analizzare gli argomenti della riga di comando con optparse o argparse (disponibile dal 2.7 o 3.2) di scegliere quale camera che si desidera eseguire, veloce, lento o tutti.

In alternativa, ci si può fidare che sys.argv[1] è uno dei tre valori e utilizzare qualcosa di semplice come questo

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

Altri suggerimenti

Per eseguire un solo test specifico è possibile utilizzare:

$ python -m unittest test_module.TestClass.test_method

Maggiori informazioni qui

In realtà, si può passare i nomi dei test case come sys.argv e solo i casi saranno testati.

Per esempio, supponiamo di avere

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

È possibile chiamare

python test.py account

avere solo i test di conto, o anche

$ python test.py account customer

di avere entrambi i casi testati

Sto facendo questo con un semplice skipIf:

import os

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

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

In questo modo ho solo bisogno di decorare un banco di prova già esistente con questa singola linea (non c'è bisogno di creare suite di test o simili, solo che una os.getenv() linea di chiamata all'inizio del mio file di test di unità), e come impostazione predefinita questo test viene saltato.

Se voglio eseguirlo nonostante sia lento, mi basta chiamare il mio script come questo:

SLOW_TESTS=1 python -m unittest …

Hai fondamentalmente due modi per farlo:

  1. Definisci la propria suite di test per la classe
  2. Creare classi finte della connessione cluster che restituirà i dati effettivi.

Sono un forte sostenitore di lui secondo approccio; una prova di unità dovrebbe di prova solo un'unità di codice, e non sistemi complessi (come i database o cluster). Ma mi rendo conto che non è sempre possibile; a volte, la creazione di mock up è semplicemente troppo costoso, o l'obiettivo del test è davvero nel sistema complesso.

Torna ad opzione (1), si può procedere in questo modo:

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

e poi passando la suite al test runner:

unittest.TextTestRunner().run(suite)

Maggiori informazioni sulla documentazione python: http://docs.python.org /library/unittest.html#testsuite-objects

Dal momento che si utilizza unittest.main() si può semplicemente eseguire python tests.py --help per ottenere la documentazione:

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

Cioè, si può semplicemente fare

python tests.py TestClass.test_method

In alternativa, è possibile utilizzare la funzione unittest.SkipTest(). Esempio, aggiungere un metodo skipOrRunTest alla classe di test in questo modo:

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

Quindi aggiungere una chiamata a questo metodo skipOrRunTest al proprio all'inizio di ciascuno dei vostri test di unità in questo modo:

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

ho trovato un'altra soluzione, in base a come funziona il unittest.skip decoratore. Impostando il __unittest_skip__ e __unittest_skip_why__.

basata sulle etichette

ho voluto applicare un sistema di etichettatura, per etichettare alcuni test come quick, slow, glacier, memoryhog, cpuhog, core, e così via.

Quindi eseguire all 'quick' tests, o run everything except 'memoryhog' tests, la configurazione di base whitelist / blacklist

Implementazione

ho implementato questo in 2 parti:

  1. Per prima cosa aggiungere etichette alle prove (tramite un costume @testlabel classe decoratore)
  2. Custom unittest.TestRunner per identificare quali test saltare, e modificare il contenuto-TEST prima di eseguire.

implementazione di lavoro è in questo succo: https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(un esempio completamente funzionante era troppo lungo per mettere qui)

Il risultato è ...

$ ./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)

Tutti i test di classe MyTests1 vengono saltati perché ha la foo etichetta.

--whitelist funziona anche

considerare di usare un testrunner dedicato, come py.test, naso o forse anche zope.testing. Hanno tutte le opzioni della riga di comando per la selezione di test.

Cercare per esempio come Profumo: https://pypi.python.org/pypi /nose/1.3.0

Ho provato @ risposta di Slott:

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

Ma che mi ha dato il seguente errore:

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

Di seguito ha lavorato per me:

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

Ho trovato un altro modo per selezionare il test_ * metodi che ho solo voglia di correre con l'aggiunta di un attributo a loro. Che, fondamentalmente, utilizza un metaclasse per decorare le callable all'interno della classe TestCase che hanno l'attributo StepDebug con un decoratore unittest.skip. Maggiori informazioni

saltare tutti i test unitari ma uno in Python utilizzando decoratori e metaclassi

Non so se si tratta di una soluzione migliore rispetto a quelli di cui sopra sto solo dotandola come opzione.

Non ho trovato un bel modo per farlo prima, in modo da condividere qui.

Obiettivo: ottenere una serie di file di test insieme in modo che possano essere eseguiti come un'unità, ma possiamo ancora scegliere uno qualsiasi di essi a correre da solo.

Problema: il metodo di scoperta non consente una facile selezione di un unico banco di prova per eseguire

.

Design: vedi sotto. Questo appiattisce lo spazio dei nomi in modo può selezionare da TestCase nome della classe, e lasciare fuori il il "tests1.test_core" prefisso:

./run-tests TestCore.test_fmap

Codice

  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 )

Questa è l'unica cosa che ha funzionato per me.

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

Quando ho chiamato anche se ho dovuto passare il nome del nome della classe e il test. Un po 'scomodo in quanto non ho combinazione di classe e nome del test memorizzato.

python ./tests.py class_Name.test_30311

Rimozione del nome della classe e nome del test viene eseguito tutti i test nel file. Trovo che questo sia molto più facile da affrontare poi il costruito nel metodo dal momento che in realtà non cambio il mio comando sul CLI. Basta aggiungere il parametro.

Enjoy, Keith

ho creato un decoratore che permette di marcatura test come test lenti e saltare utilizzando una variabile d'ambiente

from unittest import skip
import os

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

Ora è possibile contrassegnare i test più lento in questo modo:

@slow_test
def test_my_funky_thing():
    perform_test()

E saltare test lenti impostando la variabile SKIP_SLOW_TESTS ambiente:

SKIP_SLOW_TESTS=1 python -m unittest
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top