بيثون unittest:كيفية تشغيل فقط جزء من اختبار الملف ؟

StackOverflow https://stackoverflow.com/questions/1068246

سؤال

لدي اختبار الملف الذي يحتوي على اختبارات أخذ الكثير من الوقت (يرسلون حسابات مجموعة وانتظر النتيجة).كل هذه هي محددة في TestCase الدرجة.

لأنها تأخذ وقت و علاوة على ذلك ليس من المرجح أن كسر كنت تريد أن تكون قادرة على اختيار ما إذا كان هذا فرعية من الاختبارات أو لا تشغيل (أفضل طريقة ستكون مع وسيطة سطر الأوامر ، أي "./tests.py --offline"أو شيء من هذا القبيل) ، حتى أتمكن من تشغيل معظم الاختبارات في كثير من الأحيان و بسرعة و مجموعة كاملة مرة واحدة في حين, عندما يكون لدي الوقت.

الآن أنا فقط استخدام unittest.main() لبدء الاختبارات.

شكرا

هل كانت مفيدة؟

المحلول

الافتراضي unittest.main() يستخدم الافتراضي اختبار محمل لجعل TestSuite من الوحدة التي الرئيسي هو تشغيل.

لم يكن لديك لاستخدام هذا السلوك الافتراضي.

يمكنك ، على سبيل المثال ، وجعل ثلاثة unittest.TestSuite حالات.

  1. "سريع" فرعية.

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. "بطء" فرعية.

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. "الجامع" مجموعة.

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

علما بأنني قد عدلت TestCase أسماء الإشارة السريعة مقابلبطيئة.يمكنك فرعية unittest.TestLoader تحليل أسماء الطبقات وخلق متعددة لوادر.

ثم الخاص بك الرئيسية للبرنامج يمكن تحليل سطر الأوامر مع optparse أو argparse (متاح منذ 2.7 أو 3.2) أن تختار أي جناح تريد تشغيلها بسرعة أو ببطء أو كل.

أو يمكنك أن تثق أن sys.argv[1] هو واحد من ثلاثة القيم و استخدام شيء بسيط مثل هذا

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

نصائح أخرى

لتشغيل فقط اختبار محدد واحد يمكنك استخدام:

$ python -m unittest test_module.TestClass.test_method

هنا

في الواقع، يمكن للمرء أن تمرير أسماء حالة اختبار كما sys.argv وسيتم اختبار فقط تلك الحالات.

وعلى سبيل المثال، افترض أن لديك

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

ويمكنك الاتصال

python test.py account

لديك حساب الاختبارات فقط، أو حتى

$ python test.py account customer

لديك كلتا الحالتين اختبار

وأنا أفعل هذا باستخدام skipIf بسيط:

import os

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

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

وبهذه الطريقة أحتاج فقط تزيين حالة اختبار القائمة بالفعل مع هذا سطر واحد (لا حاجة لإنشاء أجنحة اختبار أو ما شابه ذلك، لمجرد أن os.getenv() سطر واحد الدعوة في بداية ملفي اختبار وحدة)، ونتيجة لالافتراضي هذا الاختبار يحصل تخطي.

إذا أريد لتنفيذه على الرغم من كونها بطيئة، وأنا مجرد دعوة لي النصي مثل هذا:

SLOW_TESTS=1 python -m unittest …

لديك أساسا طريقتان للقيام بذلك:

  1. تحديد الخاصة بك مجموعة من اختبارات الفصل
  2. إنشاء تسخر الطبقات من مجموعة الاتصال التي ستعود البيانات الفعلية.

أنا مؤيد قوي هو النهج الثاني ؛ اختبار وحدة يجب أن الاختبار جدا فقط وحدة من التعليمات البرمجية ، وليس الأنظمة المعقدة (مثل قواعد البيانات أو مجموعات).ولكن أنا أفهم أن أنها ليست دائما ممكنة ؛ في بعض الأحيان, خلق النموذجين هو ببساطة مكلفة للغاية ، أو الهدف من الاختبار هو حقا في نظام معقد.

العودة إلى خيار (1), يمكنك المضي قدما في هذا الطريق:

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

ثم يمر الجناح إلى اختبار عداء:

unittest.TextTestRunner().run(suite)

المزيد من المعلومات حول وثائق بايثون: http://docs.python.org/library/unittest.html#testsuite-objects

ومنذ استخدام unittest.main() يمكنك فقط تشغيل python tests.py --help للحصول على وثائق:

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

وهذا هو، يمكنك أن تفعل ببساطة

python tests.py TestClass.test_method

وأو يمكنك الاستفادة من وظيفة unittest.SkipTest(). على سبيل المثال، إضافة أسلوب skipOrRunTest إلى فئة اختبار الخاصة بك مثل هذا:

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

وثم إضافة استدعاء هذا الأسلوب skipOrRunTest إلى بداية كل وحدة الاختبارات الخاصة بك مثل هذا:

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

لقد وجدت حل آخر ، استنادا إلى كيفية unittest.skip ديكور يعمل.من خلال وضع __unittest_skip__ و __unittest_skip_why__.

مستندة

أردت أن تطبيق نظام وضع العلامات ، إلى تسمية بعض الاختبارات quick, slow, glacier, memoryhog, cpuhog, core, وهكذا.

ثم تشغيل all 'quick' tests, أو run everything except 'memoryhog' tests, الخاص بك الأساسية القائمة البيضاء / القائمة السوداء الإعداد

تنفيذ

أنا نفذت هذا في 2 أجزاء:

  1. أولا إضافة تسميات إلى اختبارات (عبر مخصص @testlabel فئة ديكور)
  2. مخصص unittest.TestRunner تحديد الاختبارات التي لتخطي ، وتعديل testlist المحتوى قبل تنفيذ.

العامل التنفيذ في هذا الملخص:https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(العمل بشكل كامل سبيل المثال كانت طويلة جدا لوضع هنا)

والنتيجة هي...

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

كل MyTests1 اختبارات الصف يتم تخطي لأنه يحتوي على foo التسمية.

--whitelist يعمل أيضا

والنظر في استخدام testrunner مخصصة، مثل py.test، الأنف أو ربما حتى zope.testing. أنهم جميعا لديهم خيارات سطر الأوامر لاختيار الاختبارات.

ونظرة على سبيل المثال كما الأنف: https://pypi.python.org/pypi /nose/1.3.0

وحاولت @ الجواب slott ل:

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

ولكن هذا أعطاني الخطأ التالي:

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

وفيما يلي عملت بالنسبة لي:

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

ولقد وجدت طريقة أخرى لتحديد test_ * الأساليب التي أريد فقط لتشغيل بإضافة سمة لهم. كنت في الأساس استخدام metaclass لتزيين callables داخل الطبقة TestCase التي لديها StepDebug السمة مع الديكور unittest.skip. مزيد من المعلومات حول

تخطي كافة الاختبارات وحدة واحدة ولكن في بيثون باستخدام الديكور وmetaclasses

وأنا لا أعرف ما إذا كان هو حل أفضل من تلك المذكورة أعلاه وأنا مجرد توفير كخيار.

ولم تجد طريقة لطيفة للقيام بذلك من قبل، حتى تقاسم هنا.

الهدف: الحصول على مجموعة من الملفات اختبار معا بحيث يمكن تشغيل كوحدة واحدة، ولكن لا يزال بوسعنا أن اختيار أي واحد منهم لتشغيل من تلقاء نفسه.

المشكلة: طريقة اكتشاف لا يسمح اختيار سهل من حالة اختبار واحد لتشغيل

.

والتصميم: انظر أدناه. هذا <م> يسطح مساحة الاسم حتى يمكن تحديد بالاسم الطبقة TestCase، وترك قبالة و"tests1.test_core" بادئة:

./run-tests TestCore.test_fmap

كود

  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 )

وهذا هو الشيء الوحيد الذي عملت بالنسبة لي.

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

وعندما اتصلت ذلك على الرغم من أنني قد لتمرير في اسم اسم الفئة والاختبار. A غير مريح قليلا لأنني لم يكن لديك الصف واسم اختبار مزيج حفظه.

والثعبان ./tests.py class_Name.test_30311

وإزالة اسم فئة واسم الاختبار يدير كل الاختبارات في الملف الخاص بك. أجد هذا MUCH أكثر سهولة للتعامل مع ثم بنيت في طريقة لأنني لا تتغير حقا أمري على CLI. فقط إضافة المعلمة.

واستمتع، كيث

وأنا خلقت الديكور الذي يسمح لوضع علامات الاختبارات كما اختبارات بطيئة والقفز عليها باستخدام متغير البيئة

from unittest import skip
import os

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

والآن يمكنك وضع علامة الاختبارات الخاصة بك كما بطيئة مثل هذا:

@slow_test
def test_my_funky_thing():
    perform_test()

وتخطي اختبارات بطيئة عن طريق تعيين متغير البيئة SKIP_SLOW_TESTS:

SKIP_SLOW_TESTS=1 python -m unittest
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top