كيف يمكنني الحصول على الأنف لاكتشاف حالات الاختبار التي تم إنشاؤها ديناميكيًا؟
-
19-08-2019 - |
سؤال
هذه متابعة لـ أ السؤال السابق خاصتي.
في السؤال السابق، تم استكشاف طرق لتنفيذ ما كان في الأساس نفس الاختبار على مجموعة كاملة من الوظائف، مما يضمن عدم توقف الاختبار عند الوظيفة الأولى التي فشلت.
استخدم الحل المفضل لدي فئة تعريفية لإدراج الاختبارات ديناميكيًا في Unittest.TestCase.لسوء الحظ، الأنف لا يلتقط هذا لأن الأنف يقوم بمسح ثابت لحالات الاختبار.
كيف يمكنني اكتشاف وتشغيل مثل هذا TestCase؟يرجى الرجوع هنا للحصول على مثال لـ TestCase المعني.
المحلول
يحتوي الأنف على ميزة "مولد الاختبار" لأشياء مثل هذه.تكتب دالة مولد تنتج كل وظيفة "حالة اختبار" تريد تشغيلها، بالإضافة إلى الوسائط الخاصة بها.باتباع المثال السابق، قد يتحقق هذا من كل وظيفة في اختبار منفصل:
import unittest
import numpy
from somewhere import the_functions
def test_matrix_functions():
for function in the_functions:
yield check_matrix_function, function
def check_matrix_function(function)
matrix1 = numpy.ones((5,10))
matrix2 = numpy.identity(5)
output = function(matrix1, matrix2)
assert matrix1.shape == output.shape, \
"%s produces output of the wrong shape" % str(function)
نصائح أخرى
لا يقوم الأنف بفحص الاختبارات بشكل ثابت، لذلك أنت يستطيع استخدم سحر metaclass لإجراء الاختبارات التي يجدها Nose.
الجزء الصعب هو أن تقنيات metaclass القياسية لا تقوم بتعيين سمة func_name بشكل صحيح، وهو ما يبحث عنه Nose عند التحقق مما إذا كانت الأساليب في فصلك عبارة عن اختبارات.
إليك فئة تعريفية بسيطة.فهو يبحث في أمر func ويضيف طريقة جديدة لكل طريقة يجدها، مع التأكيد على أن الطريقة التي عثر عليها تحتوي على سلسلة مستندية.يتم إعطاء هذه الأساليب الاصطناعية الجديدة الأسماء "test_%d" %i
.
import new
from inspect import isfunction, getdoc
class Meta(type):
def __new__(cls, name, bases, dct):
newdct = dct.copy()
for i, (k, v) in enumerate(filter(lambda e: isfunction(e[1]), dct.items())):
def m(self, func):
assert getdoc(func) is not None
fname = 'test_%d' % i
newdct[fname] = new.function(m.func_code, globals(), fname,
(v,), m.func_closure)
return super(Meta, cls).__new__(cls, 'Test_'+name, bases, newdct)
الآن، لنقم بإنشاء فئة جديدة تستخدم فئة التعريف هذه
class Foo(object):
__metaclass__ = Meta
def greeter(self):
"sdf"
print 'Hello World'
def greeter_no_docstring(self):
pass
في وقت التشغيل، Foo
سيتم تسميته فعلياً Test_Foo
وسوف يكون greeter
, greeter_no_docstring
, test_1
و test_2
كأساليبها.عندما أركض nosetests
في هذا الملف، وهنا الإخراج:
$ nosetests -v test.py
test.Test_Foo.test_0 ... FAIL
test.Test_Foo.test_1 ... ok
======================================================================
FAIL: test.Test_Foo.test_0
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/Users/rmcgibbo/Desktop/test.py", line 10, in m
assert getdoc(func) is not None
AssertionError
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (failures=1)
هذه الفئة التعريفية ليست مفيدة حقًا كما هي، ولكن إذا كنت تستخدم بدلاً من ذلك Meta
ليس كفئة وصفية مناسبة، ولكن كفئة وصفية وظيفية (على سبيل المثال.يأخذ فئة كوسيطة ويعيد فئة جديدة، فئة تمت إعادة تسميتها حتى يتمكن الأنف من العثور عليها)، ثم يكون مفيد.لقد استخدمت هذا الأسلوب لاختبار التزام سلاسل المستندات بمعيار Numpy تلقائيًا كجزء من مجموعة اختبار الأنف.
أيضًا، واجهت صعوبة كبيرة في الحصول على الإغلاق المناسب للعمل مع new.function، ولهذا السبب يستخدم هذا الرمز m(self, func)
أين func
تم جعله وسيطة افتراضية.سيكون من الطبيعي أكثر استخدام الإغلاق value
, ، ولكن لا يبدو أن هذا ينجح.
يمكنك محاولة إنشاء فئات testcase باستخدام type()
class UnderTest_MixIn(object):
def f1(self, i):
return i + 1
def f2(self, i):
return i + 2
SomeDynamicTestcase = type(
"SomeDynamicTestcase",
(UnderTest_MixIn, unittest.TestCase),
{"even_more_dynamic":"attributes .."}
)
# or even:
name = 'SomeDynamicTestcase'
globals()[name] = type(
name,
(UnderTest_MixIn, unittest.TestCase),
{"even_more_dynamic":"attributes .."}
)
يجب إنشاء هذا عندما يحاول الأنف استيراد test_module الخاص بك لذلك يجب أن يعمل.
وتتمثل ميزة هذا الأسلوب في أنه يمكنك إنشاء العديد من مجموعات الاختبارات ديناميكيًا.