Unittest.TestCase komut satırından tek test çalıştırılıyor


257

Ekibimizde, çoğu test örneğini şöyle tanımlarız:

Bir "çerçeve" sınıfı ourtcfw.py:

import unittest

class OurTcFw(unittest.TestCase):
    def setUp:
        # something

    # other stuff that we want to use everywhere

ve testMyCase.py gibi birçok test durumu:

import localweather

class MyCase(OurTcFw):

    def testItIsSunny(self):
        self.assertTrue(localweather.sunny)

    def testItIsHot(self):
        self.assertTrue(localweather.temperature > 20)

if __name__ == "__main__":
    unittest.main()

Yeni test kodu yazarken ve sık sık çalıştırmak ve zaman kazanmak istiyorum, yaptığım diğer testlerin önüne "__" koymak olduğunu. Ama hantal, yazdığım kod beni rahatsız ediyor ve bu yarattığı taahhüt gürültü sataşmak rahatsız edici.

Yani örneğin değişiklik yaparken testItIsHot(), bunu yapabilmek istiyorum:

$ python testMyCase.py testItIsHot

ve adres unittestçalıştırmak sadece testItIsHot()

Bunu nasıl başarabilirim?

Parçayı yeniden yazmaya çalıştım if __name__ == "__main__":, ama Python'da yeni olduğum için, kendimi kayıp hissediyorum ve yöntemlerden başka her şeye daldı.

Yanıtlar:


311

Bu önerdiğiniz gibi çalışır - sadece sınıf adını da belirtmeniz gerekir:

python testMyCase.py MyCase.testItIsHot

2
Aman! Testler python2.6 üzerinde çalıştırılacak olduğundan (% 99 zaman ben yapabilirsiniz , ben 2.6.8 doc bakarak ve daha kaçırılan testler kendileri python2.7 ile sınamak)! :-)
Alois Mahdal

1
Sadece bu yöntem sadece "test *" olarak adlandırılırsa işe yaradığını fark etti, bu yüzden ne yazık ki yeniden adlandırma ile "devre dışı" testi çalıştırmak için kullanılamaz
Alois Mahdal

4
Bir alt dizindeki testler için çalışmaz - olgun bir Python programındaki en yaygın durum.
Tom Swirly

4
@TomSwirly Şimdi kontrol edemiyorum ama __init__.pybu dizin içinde (ve varsa alt dizinlerde ) oluşturarak (boş ) ve örneğin arayarak bunu yapabileceğinizi düşünüyorum . python test/testMyCase.py test.MyCase.testItIsHot.
Alois Mahdal

1
Bunu yaptığımda hiçbir şey olmuyor. Geçici çözümler buldum, ancak bu yöntemin benim için çalışacağını umuyordum.
Joe Flack

153

Test durumlarınızı düzenlerseniz, yani, gerçek kodla aynı kuruluşu izleyin ve aynı paketteki modüller için göreli içe aktarımları kullanın

Aşağıdaki komut biçimini de kullanabilirsiniz:

python -m unittest mypkg.tests.test_module.TestClass.test_method
# In your case, this would be:
python -m unittest testMyCase.MyCase.testItIsHot

Bunun için Python3 belgeleri: https://docs.python.org/3/library/unittest.html#command-line-interface


Bu çok beceriksizce Java esque. "long_module_name.SameLongNameAsAClass.test_long_name_beginning_with_test_as_a_convention" ... umarım kodlarını test eden aklı başında bir insan gibi modüler olmamanız dileğiyle.
Joshua Detwiler

69

Tahmin ettiğiniz gibi iyi çalışabilir

python testMyCase.py MyCase.testItIsHot

Ve sadece test etmenin başka bir yolu var testItIsHot:

    suite = unittest.TestSuite()
    suite.addTest(MyCase("testItIsHot"))
    runner = unittest.TextTestRunner()
    runner.run(suite)

11
Bu cevabın ikinci bölümünü son derece yararlı buldum: Eclipse + PyDev'de testler yazıyorum ve komut satırına geçmek istemiyorum!
Giovanni Di Milia

25

Unittest modülünün yardımına bakarsanız, bir modülden test senaryosu sınıflarını ve test senaryosu sınıfından test yöntemlerini çalıştırmanıza izin veren birkaç kombinasyon hakkında bilgi verir.

python3 -m unittest -h

[...]

Examples:
  python3 -m unittest test_module               - run tests from test_module
  python3 -m unittest module.TestClass          - run tests from module.TestClass
  python3 -m unittest module.Class.test_method  - run specified test method

unittest.main()Modülünüzün varsayılan davranışı olarak a tanımlamanızı gerektirmez .


2
1 ve terminoloji beri bir dile yeni eğer kafa karıştırıcı (ve edilebilmektedir usagehatta garip bir şekilde tutarsız): koşu python -m unittest module_test.TestClass.test_methoddosya varsayar module_test.py(geçerli dizinden çalıştırın ve __init.py__edilir değil gerekli); ve module_test.pyiçeren class TestClass(unittest.TestCase)...içerir def test_method(self,...)(bu da benim için python 2.7.13 üzerinde çalışır)
michael

11

Belki biri için yararlı olacaktır. Yalnızca belirli sınıftan sınama yapmak istiyorsanız:

if __name__ == "__main__":
    unittest.main(MyCase())

3.6 Python benim için çalışıyor


3

@Yarkee esinlenerek Zaten var bazı kod ile kombine. Bunu sadece run_unit_tests()komut satırını kullanmadan işlevi çağırarak veya komut satırından çağırarak başka bir komut dosyasından da çağırabilirsiniz python3 my_test_file.py.

import my_test_file
my_test_file.run_unit_tests()

Ne yazık ki bu sadece Python 3.3ya da daha üstün:

import unittest

class LineBalancingUnitTests(unittest.TestCase):

    @classmethod
    def setUp(self):
        self.maxDiff = None

    def test_it_is_sunny(self):
        self.assertTrue("a" == "a")

    def test_it_is_hot(self):
        self.assertTrue("a" != "b")

Koşucu kodu:

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from .somewhere import LineBalancingUnitTests

def create_suite(classes, unit_tests_to_run):
    suite = unittest.TestSuite()
    unit_tests_to_run_count = len( unit_tests_to_run )

    for _class in classes:
        _object = _class()
        for function_name in dir( _object ):
            if function_name.lower().startswith( "test" ):
                if unit_tests_to_run_count > 0 \
                        and function_name not in unit_tests_to_run:
                    continue
                suite.addTest( _class( function_name ) )
    return suite

def run_unit_tests():
    runner = unittest.TextTestRunner()
    classes =  [
        LineBalancingUnitTests,
    ]

    # Comment all the tests names on this list, to run all Unit Tests
    unit_tests_to_run =  [
        "test_it_is_sunny",
        # "test_it_is_hot",
    ]
    runner.run( create_suite( classes, unit_tests_to_run ) )

if __name__ == "__main__":
    print( "\n\n" )
    run_unit_tests()

Kodu biraz düzenleyerek, aramak istediğiniz tüm birim testlerini içeren bir dizi geçirebilirsiniz:

...
def run_unit_tests(unit_tests_to_run):
    runner = unittest.TextTestRunner()

    classes = \
    [
        LineBalancingUnitTests,
    ]

    runner.run( suite( classes, unit_tests_to_run ) )
...

Ve başka bir dosya:

import my_test_file

# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
    "test_it_is_sunny",
    # "test_it_is_hot",
]

my_test_file.run_unit_tests( unit_tests_to_run )

Alternatif olarak, https://docs.python.org/3/library/unittest.html#load-tests-protocol kullanabilir ve test modülünüzde / dosyanızda aşağıdaki yöntemi tanımlayabilirsiniz:

def load_tests(loader, standard_tests, pattern):
    suite = unittest.TestSuite()

    # To add a single test from this file
    suite.addTest( LineBalancingUnitTests( 'test_it_is_sunny' ) )

    # To add a single test class from this file
    suite.addTests( unittest.TestLoader().loadTestsFromTestCase( LineBalancingUnitTests ) )

    return suite

Yürütmeyi tek bir sınama dosyasıyla sınırlamak istiyorsanız, sınama bulma desenini load_tests()işlevi tanımladığınız tek dosya olarak ayarlamanız yeterlidir .

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import unittest

test_pattern = 'mytest/module/name.py'
PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )

loader = unittest.TestLoader()
start_dir = os.path.join( PACKAGE_ROOT_DIRECTORY, 'testing' )

suite = loader.discover( start_dir, test_pattern )
runner = unittest.TextTestRunner( verbosity=2 )
results = runner.run( suite )

print( "results: %s" % results )
print( "results.wasSuccessful: %s" % results.wasSuccessful() )

sys.exit( not results.wasSuccessful() )

Referanslar:

  1. Unittest modülü bir komut dosyasındayken sys.argv [1] ile ilgili sorun
  2. Bir Python sınıfındaki tüm fonksiyonları gözden geçirmek ve yürütmek için bir yol var mı?
  3. Python'da bir sınıfın tüm üye değişkenleri üzerinde döngü

Son ana program örneğine alternatif olarak, unittest.main()yöntem uygulamasını okuduktan sonra aşağıdaki varyasyonu buldum :

  1. https://github.com/python/cpython/blob/master/Lib/unittest/main.py#L65
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import unittest

PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )
start_dir = os.path.join( PACKAGE_ROOT_DIRECTORY, 'testing' )

from testing_package import main_unit_tests_module
testNames = ["TestCaseClassName.test_nameHelloWorld"]

loader = unittest.TestLoader()
suite = loader.loadTestsFromNames( testNames, main_unit_tests_module )

runner = unittest.TextTestRunner(verbosity=2)
results = runner.run( suite )

print( "results: %s" % results )
print( "results.wasSuccessful: %s" % results.wasSuccessful() )
sys.exit( not results.wasSuccessful() )

3

TL; DR : Bu büyük olasılıkla işe yarar:

python mypkg/tests/test_module.py MyCase.testItIsHot

Açıklama :

  • Uygun yolu

    python mypkg/tests/test_module.py MyCase.testItIsHot

    ANCAK onun sözde varsayımı zaten test dosyanızın içinde (genellikle sonunda) bu geleneksel kod snippet sahip olmasıdır.

    if __name__ == "__main__":
        unittest.main()
  • Uygunsuz yol

    python -m unittest mypkg.tests.test_module.TestClass.test_method

    bu if __name__ == "__main__": unittest.main()kod snippet'inin test kaynak dosyanızda olmasını gerektirmeden her zaman çalışır .

Öyleyse 2. yöntem neden uygunsuz olarak değerlendiriliyor? Çünkü uzun, nokta ile sınırlandırılmış yolu elle yazmak (( vücut bölümünüzden birini buraya ekleyin _) içinde bir acı olacaktır . 1. yöntemdeyken, mypkg/tests/test_module.pyparça modern bir kabuk veya editörünüz tarafından otomatik olarak tamamlanabilir.

Not: Vücut kısmının belinizin altında bir yerde olduğunu düşünüyorsanız, otantik bir insansınız. :-) "Parmak eklemi" demek istiyorum. Eklemleriniz için çok fazla yazmak kötü olurdu. ;-)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.