Chạy thử nghiệm đơn từ unittest.TestCase qua dòng lệnh


257

Trong nhóm của chúng tôi, chúng tôi xác định hầu hết các trường hợp thử nghiệm như thế này:

Một lớp "khung" ourtcfw.py:

import unittest

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

    # other stuff that we want to use everywhere

và rất nhiều trường hợp thử nghiệm như 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()

Khi tôi viết mã kiểm tra mới và muốn chạy nó thường xuyên và tiết kiệm thời gian, điều tôi làm là tôi đặt "__" trước tất cả các thử nghiệm khác. Nhưng nó cồng kềnh, làm tôi mất tập trung vào mã tôi đang viết và tiếng ồn cam kết mà nó tạo ra thật khó chịu.

Vì vậy, ví dụ khi thực hiện thay đổi testItIsHot(), tôi muốn có thể làm điều này:

$ python testMyCase.py testItIsHot

chỉunittest chạy testItIsHot()

Làm thế nào tôi có thể đạt được điều đó?

Tôi đã cố gắng viết lại if __name__ == "__main__":phần đó, nhưng vì tôi chưa quen với Python, tôi cảm thấy lạc lõng và tiếp tục lao vào mọi thứ khác ngoài các phương thức.

Câu trả lời:


311

Điều này hoạt động như bạn đề xuất - bạn chỉ cần xác định tên lớp là tốt:

python testMyCase.py MyCase.testItIsHot

2
Ôi trời! Vì các thử nghiệm sẽ được chạy trên python2.6 (99% thời gian tôi có thể tự kiểm tra các thử nghiệm với python2.7), tôi đã xem xét 2.6.8 doc và đã bỏ lỡ rất nhiều! :-)
Alois Mahdal

1
Chỉ lưu ý rằng điều này chỉ hoạt động nếu phương thức được gọi là "test *", vì vậy thật không may, đôi khi nó không thể được sử dụng để chạy thử nghiệm bị "vô hiệu hóa" bằng cách đổi tên
Alois Mahdal

4
Không hoạt động cho các thử nghiệm trong thư mục con - trường hợp phổ biến nhất trong chương trình Python trưởng thành.
Tom Swirly

4
@TomSwirly Không thể kiểm tra ngay bây giờ nhưng tôi nghĩ bạn có thể làm điều đó bằng cách tạo (trống) __init__.pybên trong thư mục đó (và thư mục con, nếu có) và gọi ví dụ. python test/testMyCase.py test.MyCase.testItIsHot.
Alois Mahdal

1
Không có gì xảy ra khi tôi làm điều này. Tôi đã tìm thấy cách giải quyết, nhưng tôi đã hy vọng phương pháp này sẽ hiệu quả với tôi.
Joe Flack

152

Nếu bạn tổ chức các trường hợp thử nghiệm của mình, nghĩa là, hãy theo cùng một tổ chức như mã thực tế và cũng sử dụng nhập tương đối cho các mô-đun trong cùng một gói

Bạn cũng có thể sử dụng định dạng lệnh sau:

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

Tài liệu Python3 cho việc này: https://docs.python.org/3/l Library / unittest.html # command-line-interface


Điều này rất vụng về Java-esque. "long_module_name.SameLongNameAsAClass.test_long_name_beginning_with_test_as_a_convent" ... tốt hơn là hy vọng bạn không mô đun hóa thành các bộ như một người lành mạnh kiểm tra mã của họ.
Joshua Detwiler 16/03/19

69

Nó có thể hoạt động tốt như bạn đoán

python testMyCase.py MyCase.testItIsHot

Và có một cách khác để kiểm tra testItIsHot:

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

11
Tôi thấy phần thứ hai của câu trả lời này cực kỳ hữu ích: Tôi đang viết các bài kiểm tra trong Eclipse + PyDev và tôi không muốn chuyển sang dòng lệnh!
Giovanni Di Milia

25

Nếu bạn kiểm tra sự trợ giúp của mô-đun không đáng tin cậy nhất, nó sẽ cho bạn biết về một số kết hợp cho phép bạn chạy các lớp trường hợp thử nghiệm từ một mô-đun và phương thức thử nghiệm từ một lớp trường hợp thử nghiệm.

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

Nó không yêu cầu bạn xác định một unittest.main()hành vi mặc định của mô-đun của bạn.


2
+1 và từ ngữ có thể gây nhầm lẫn nếu mới sang ngôn ngữ (và usagethậm chí là kỳ quặc không phù hợp): chạy python -m unittest module_test.TestClass.test_methodgiả định một tập tin module_test.py(chạy từ thư mục hiện hành, và __init.py__được không bắt buộc); và module_test.pychứa class TestClass(unittest.TestCase)...cái nào chứa def test_method(self,...)(cái này cũng hoạt động với tôi trên python 2.7.13)
michael

11

Có lẽ, nó sẽ hữu ích cho ai đó. Trong trường hợp bạn chỉ muốn chạy thử nghiệm từ lớp cụ thể:

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

Nó hoạt động với tôi trong python 3.6


3

Lấy cảm hứng từ @yarkee Tôi đã kết hợp nó với một số mã tôi đã có. Bạn cũng có thể gọi lệnh này từ một tập lệnh khác, chỉ bằng cách gọi hàm run_unit_tests()mà không yêu cầu sử dụng dòng lệnh hoặc chỉ gọi nó từ dòng lệnh với python3 my_test_file.py.

import my_test_file
my_test_file.run_unit_tests()

Đáng buồn thay, điều này chỉ làm việc cho Python 3.3hoặc cấp trê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")

Mã người chạy:

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

Chỉnh sửa mã một chút, bạn có thể vượt qua một mảng với tất cả các bài kiểm tra đơn vị bạn muốn gọi:

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

    classes = \
    [
        LineBalancingUnitTests,
    ]

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

Và một tập tin khác:

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 )

Ngoài ra, bạn có thể sử dụng https://docs.python.org/3/l Library / unittest.html # load-tests-protatio và xác định phương pháp sau trên mô-đun / tệp thử nghiệm của bạn:

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

Nếu bạn muốn giới hạn thực thi trong một tệp thử nghiệm duy nhất, bạn chỉ cần đặt mẫu khám phá thử nghiệm thành tệp duy nhất nơi bạn đã xác định load_tests()hàm.

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

Người giới thiệu:

  1. Sự cố với sys.argv [1] khi mô-đun unittest nằm trong tập lệnh
  2. Có cách nào lặp lại và thực hiện tất cả các hàm trong một lớp Python không?
  3. lặp qua tất cả các biến thành viên của một lớp trong python

Ngoài ra, đến ví dụ chương trình chính cuối cùng, tôi đã đưa ra biến thể sau đây sau khi đọc unittest.main()phương thức thực hiện:

  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 : Điều này rất có thể sẽ hoạt động:

python mypkg/tests/test_module.py MyCase.testItIsHot

Giải thích :

  • Cách thuận tiện

    python mypkg/tests/test_module.py MyCase.testItIsHot

    sẽ hoạt động NHƯNG giả định bất thành văn của nó là bạn đã có đoạn mã thông thường này bên trong (thường là ở cuối) tệp thử nghiệm của bạn.

    if __name__ == "__main__":
        unittest.main()
  • Cách bất tiện

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

    sẽ luôn hoạt động mà không yêu cầu bạn phải có if __name__ == "__main__": unittest.main()đoạn mã đó trong tệp nguồn thử nghiệm của bạn.

Vậy tại sao phương pháp thứ 2 lại coi là bất tiện? Bởi vì sẽ là một nỗi đau trong (_ chèn một phần cơ thể của bạn vào đây _) để gõ đường dẫn dài, được phân cách bằng dấu chấm đó bằng tay. Trong khi ở phương thức 1,mypkg/tests/test_module.py phần có thể được tự động hoàn thành, bằng trình bao hiện đại hoặc bởi trình soạn thảo của bạn.

Tái bút: Nếu bạn nghĩ rằng phần cơ thể ở đâu đó bên dưới thắt lưng của bạn, bạn là một người đích thực. :-) Ý tôi là nói "khớp ngón tay". Gõ quá nhiều sẽ có hại cho khớp của bạn. ;-)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.