我怎样才能避免从元class 派生的动态生成的classes 不以相同的class 结束?
How can I avoid dynamically generated classes derived from metaclass not to end up as the same class?
我想做的是对一个函数执行数百个单元测试,我可以从字典中得出这些单元测试。不幸的是,我不能使用任何现有的包进行参数化测试(比如鼻子),所以我试图找到我自己的解决方案。
我对以下示例代码的意图是创建 3 个 classes(每个测试一个),它们将存在于全局范围内,以便 unittests 可以选择它并 运行 相应的测试。
tests = [
{'text': 'text1fdskla3fsda4',
'result': [1, 3, 4],
},
{'text': 'fdsg45tg5b',
'result': [4, 5, 5,5 ],
},
{'text': 'fsddf4',
'result': [4, 2],
}
]
def evaluate(text):
out = []
for char in text:
if char.isdigit():
out.append(int(char))
return out
class TestMeta(type):
def __new__(cls, name, bases, attrs):
name = str(test['text'])
return type.__new__(cls, name, (unittest.TestCase,), attrs)
for test in tests:
class T(object):
__metaclass__ = TestMeta
def testOne(self):
self.assertEqual(test['result'], evaluate(test['text']))
globals()[(test['text'])] = copy.deepcopy(T)
unittest.main()
当我 运行 上面的代码时,我得到了四个单元测试,比预期的多了一个,但最重要的是,没有每个单元测试的输出,似乎 class 我创建的总是一样的(即使我实际上为每个设置了不同的名称和参数):
======================================================================
FAIL: testOne (__main__.fsddf4)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
======================================================================
FAIL: testOne (__main__.fdsg45tg5b)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
======================================================================
FAIL: testOne (__main__.fsddf4)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
======================================================================
FAIL: testOne (__main__.text1fdskla3fsda4)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
----------------------------------------------------------------------
Ran 4 tests in 0.002s
FAILED (failures=4)
deepcopy 试图获得不同的输出,但没有帮助。在全局字典中显式创建 class 是因为在 for 循环中简单地创建 classes 只会产生一个单元测试。
除了深入尝试元所有内容之外,您 运行 遇到了一个典型的 Python 初学者问题:全局名称查找在运行时完成。
因此,在您的代码中:
for test in tests:
class T(object):
__metaclass__ = TestMeta
def testOne(self):
self.assertEqual(test['result'], evaluate(test['text']))
当 testOne
运行时,它会在 globals
字典中查找 test
当时 -- 它 runs -- 当然,此时 test
已设置为最近设置的值。
您需要强制绑定更早发生,您可以通过更改
来做到这一点
def testOne(self):
进入
def testOne(self, test=test):
此更改强制在 def
执行时查找全局 test
(相对于稍后的 body方法执行),这与 class
语句同时执行——即,当全局变量 test
设置为列表 tests
的当前项时,循环的每个分支执行一次。
我想做的是对一个函数执行数百个单元测试,我可以从字典中得出这些单元测试。不幸的是,我不能使用任何现有的包进行参数化测试(比如鼻子),所以我试图找到我自己的解决方案。
我对以下示例代码的意图是创建 3 个 classes(每个测试一个),它们将存在于全局范围内,以便 unittests 可以选择它并 运行 相应的测试。
tests = [
{'text': 'text1fdskla3fsda4',
'result': [1, 3, 4],
},
{'text': 'fdsg45tg5b',
'result': [4, 5, 5,5 ],
},
{'text': 'fsddf4',
'result': [4, 2],
}
]
def evaluate(text):
out = []
for char in text:
if char.isdigit():
out.append(int(char))
return out
class TestMeta(type):
def __new__(cls, name, bases, attrs):
name = str(test['text'])
return type.__new__(cls, name, (unittest.TestCase,), attrs)
for test in tests:
class T(object):
__metaclass__ = TestMeta
def testOne(self):
self.assertEqual(test['result'], evaluate(test['text']))
globals()[(test['text'])] = copy.deepcopy(T)
unittest.main()
当我 运行 上面的代码时,我得到了四个单元测试,比预期的多了一个,但最重要的是,没有每个单元测试的输出,似乎 class 我创建的总是一样的(即使我实际上为每个设置了不同的名称和参数):
======================================================================
FAIL: testOne (__main__.fsddf4)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
======================================================================
FAIL: testOne (__main__.fdsg45tg5b)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
======================================================================
FAIL: testOne (__main__.fsddf4)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
======================================================================
FAIL: testOne (__main__.text1fdskla3fsda4)
----------------------------------------------------------------------
Traceback (most recent call last):
File "ble.py", line 45, in testOne
self.assertEqual(test['result'], evaluate(test['text']))
AssertionError: [4, 2] != [4]
----------------------------------------------------------------------
Ran 4 tests in 0.002s
FAILED (failures=4)
deepcopy 试图获得不同的输出,但没有帮助。在全局字典中显式创建 class 是因为在 for 循环中简单地创建 classes 只会产生一个单元测试。
除了深入尝试元所有内容之外,您 运行 遇到了一个典型的 Python 初学者问题:全局名称查找在运行时完成。
因此,在您的代码中:
for test in tests:
class T(object):
__metaclass__ = TestMeta
def testOne(self):
self.assertEqual(test['result'], evaluate(test['text']))
当 testOne
运行时,它会在 globals
字典中查找 test
当时 -- 它 runs -- 当然,此时 test
已设置为最近设置的值。
您需要强制绑定更早发生,您可以通过更改
来做到这一点 def testOne(self):
进入
def testOne(self, test=test):
此更改强制在 def
执行时查找全局 test
(相对于稍后的 body方法执行),这与 class
语句同时执行——即,当全局变量 test
设置为列表 tests
的当前项时,循环的每个分支执行一次。