بيثون unittest:كيفية تشغيل فقط جزء من اختبار الملف ؟
-
21-08-2019 - |
سؤال
لدي اختبار الملف الذي يحتوي على اختبارات أخذ الكثير من الوقت (يرسلون حسابات مجموعة وانتظر النتيجة).كل هذه هي محددة في TestCase الدرجة.
لأنها تأخذ وقت و علاوة على ذلك ليس من المرجح أن كسر كنت تريد أن تكون قادرة على اختيار ما إذا كان هذا فرعية من الاختبارات أو لا تشغيل (أفضل طريقة ستكون مع وسيطة سطر الأوامر ، أي "./tests.py --offline
"أو شيء من هذا القبيل) ، حتى أتمكن من تشغيل معظم الاختبارات في كثير من الأحيان و بسرعة و مجموعة كاملة مرة واحدة في حين, عندما يكون لدي الوقت.
الآن أنا فقط استخدام unittest.main()
لبدء الاختبارات.
شكرا
المحلول
الافتراضي unittest.main()
يستخدم الافتراضي اختبار محمل لجعل TestSuite من الوحدة التي الرئيسي هو تشغيل.
لم يكن لديك لاستخدام هذا السلوك الافتراضي.
يمكنك ، على سبيل المثال ، وجعل ثلاثة unittest.TestSuite حالات.
"سريع" فرعية.
fast = TestSuite() fast.addTests( TestFastThis ) fast.addTests( TestFastThat )
"بطء" فرعية.
slow = TestSuite() slow.addTests( TestSlowAnother ) slow.addTests( TestSlowSomeMore )
"الجامع" مجموعة.
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), يمكنك المضي قدما في هذا الطريق:
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 أجزاء:
- أولا إضافة تسميات إلى اختبارات (عبر مخصص
@testlabel
فئة ديكور) - مخصص
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