كيف يمكنني الحصول على الأنف لاكتشاف حالات الاختبار التي تم إنشاؤها ديناميكيًا؟

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

  •  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 الخاص بك لذلك يجب أن يعمل.

وتتمثل ميزة هذا الأسلوب في أنه يمكنك إنشاء العديد من مجموعات الاختبارات ديناميكيًا.

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