Menjalankan tes tunggal dari unittest.TestCase melalui baris perintah


257

Di tim kami, kami mendefinisikan sebagian besar kasus uji seperti ini:

Satu kelas "kerangka kerja" ourtcfw.py:

import unittest

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

    # other stuff that we want to use everywhere

dan banyak kasus uji seperti testMyCase.py:

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()

Ketika saya sedang menulis kode tes baru dan ingin sering menjalankannya, dan menghemat waktu, apa yang saya lakukan adalah saya meletakkan "__" di depan semua tes lainnya. Tapi itu merepotkan, mengalihkan saya dari kode yang saya tulis dan suara komit yang dibuatnya ini benar-benar menjengkelkan.

Jadi misalnya ketika membuat perubahan testItIsHot(), saya ingin dapat melakukan ini:

$ python testMyCase.py testItIsHot

dan telah unittestberjalan saja testItIsHot()

Bagaimana saya bisa mencapainya?

Saya mencoba menulis ulang if __name__ == "__main__":bagian itu, tetapi karena saya baru di Python, saya merasa tersesat dan terus menabrak segala sesuatu selain metode.

Jawaban:


311

Ini berfungsi seperti yang Anda sarankan - Anda hanya perlu menentukan nama kelas juga:

python testMyCase.py MyCase.testItIsHot

2
Astaga! Karena tes harus dijalankan pada python2.6 (99% dari waktu saya dapat menguji tes sendiri dengan python2.7), saya melihat 2.6.8 doc dan sangat ketinggalan! :-)
Alois Mahdal

1
Hanya memperhatikan bahwa ini hanya berfungsi jika metode ini disebut "test *", jadi sayangnya itu tidak dapat digunakan untuk sesekali menjalankan tes yang "dinonaktifkan" dengan mengganti nama
Alois Mahdal

4
Tidak berfungsi untuk pengujian dalam subdirektori - kasus paling umum dalam program Python dewasa.
Tom Swirly

4
@ TomSwirly Tidak dapat memeriksa sekarang tapi saya pikir Anda bisa melakukannya dengan membuat (kosong) __init__.pydi dalam direcrory (dan subdirs, jika ada) dan memanggil mis. python test/testMyCase.py test.MyCase.testItIsHot.
Alois Mahdal

1
Tidak ada yang terjadi ketika saya melakukan ini. Saya menemukan solusi, tetapi saya berharap metode ini akan berhasil untuk saya.
Joe Flack

152

Jika Anda mengatur kasus pengujian Anda, yaitu, ikuti organisasi yang sama seperti kode aktual dan juga gunakan impor relatif untuk modul dalam paket yang sama

Anda juga dapat menggunakan format perintah berikut:

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

Dokumentasi Python3 untuk ini: https://docs.python.org/3/library/unittest.html#command-line-interface


Ini sangat aneh Jawa-esque. "long_module_name.SameLongNameAsAClass.test_long_name_beginning_with_test_as_a_convention" ... sebaiknya Anda tidak memodulasi ke suite seperti orang waras yang menguji kode mereka.
Joshua Detwiler

69

Dapat bekerja dengan baik seperti yang Anda duga

python testMyCase.py MyCase.testItIsHot

Dan ada cara lain untuk hanya menguji testItIsHot:

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

11
Saya menemukan bagian kedua dari jawaban ini sangat membantu: Saya menulis tes di Eclipse + PyDev dan saya tidak ingin beralih ke baris perintah!
Giovanni Di Milia

25

Jika Anda memeriksa bantuan modul unittest, ia memberi tahu Anda tentang beberapa kombinasi yang memungkinkan Anda untuk menjalankan kelas kasus uji dari modul dan metode uji dari kelas kasus uji.

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

Itu tidak mengharuskan Anda untuk mendefinisikan unittest.main()sebagai perilaku default modul Anda.


2
1 dan karena terminologi dapat membingungkan jika baru ke bahasa (dan usagebahkan anehnya tidak konsisten): berjalan python -m unittest module_test.TestClass.test_methodmengasumsikan file module_test.py(dijalankan dari direktori saat ini, dan __init.py__ini tidak diperlukan); dan module_test.pyberisi class TestClass(unittest.TestCase)...yang berisi def test_method(self,...)(ini juga berfungsi untuk saya di python 2.7.13)
michael

11

Mungkin, itu akan bermanfaat bagi seseorang. Jika Anda ingin menjalankan hanya tes dari kelas tertentu:

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

Ini berfungsi untuk saya dengan python 3.6


3

Terinspirasi oleh @yarkee saya menggabungkannya dengan beberapa kode yang sudah saya dapatkan. Anda juga dapat memanggil ini dari skrip lain, hanya dengan memanggil fungsi run_unit_tests()tanpa harus menggunakan baris perintah, atau cukup memanggilnya dari baris perintah dengan python3 my_test_file.py.

import my_test_file
my_test_file.run_unit_tests()

Sayangnya ini hanya berfungsi untuk Python 3.3atau lebih unggul:

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

Kode pelari:

#! /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()

Mengedit sedikit kode, Anda dapat melewati array dengan semua tes unit yang ingin Anda panggil:

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

    classes = \
    [
        LineBalancingUnitTests,
    ]

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

Dan file lain:

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 )

Atau, Anda dapat menggunakan https://docs.python.org/3/library/unittest.html#load-tests-protocol dan tentukan metode berikut pada modul / file pengujian Anda:

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

Jika Anda ingin membatasi eksekusi ke satu file uji tunggal, Anda hanya perlu mengatur pola penemuan tes untuk satu-satunya file tempat Anda mendefinisikan load_tests()fungsi.

#! /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() )

Referensi:

  1. Masalah dengan sys.argv [1] ketika modul unittest ada dalam skrip
  2. Apakah ada cara untuk mengulang dan menjalankan semua fungsi dalam kelas Python?
  3. perulangan semua variabel anggota kelas dalam python

Atau contoh program utama terakhir, saya datang dengan variasi berikut setelah membaca unittest.main()implementasi metode:

  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 : Ini kemungkinan besar akan berhasil:

python mypkg/tests/test_module.py MyCase.testItIsHot

Penjelasannya :

  • Cara yang nyaman

    python mypkg/tests/test_module.py MyCase.testItIsHot

    akan bekerja tetapi asumsi tak terucapkan adalah Anda sudah memiliki potongan kode konvensional ini di dalam (biasanya di akhir) file tes Anda.

    if __name__ == "__main__":
        unittest.main()
  • Cara yang tidak nyaman

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

    akan selalu berfungsi, tanpa mengharuskan Anda memiliki if __name__ == "__main__": unittest.main()cuplikan kode di file sumber pengujian Anda.

Jadi mengapa metode ke-2 dianggap tidak nyaman? Karena akan terasa sakit di (_ masukkan salah satu bagian tubuh Anda di sini _) untuk mengetikkan panjang itu, jalur yang dibatasi titik dengan tangan. Sedangkan dalam metode 1, mypkg/tests/test_module.pybagian dapat diselesaikan secara otomatis, baik oleh shell modern, atau oleh editor Anda.

NB: Jika Anda mengira bagian tubuh itu di bawah pinggang Anda, Anda orang yang asli. :-) Maksud saya mengatakan "finger joint". Terlalu banyak mengetik akan berdampak buruk bagi persendian Anda. ;-)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.