如何在TDD中检查方法是否存在?
在严格的测试驱动开发方法中,每一步都必须提前进行测试。甚至一个类或它的方法是否存在,也必须在实际创建之前就进行测试。
我遇到了一个问题,就是如何写测试来检查一个方法是否存在。
class BasicTests(unittest.TestCase):
def setUp(self):
self.test = RandomGenClass()
def testRandomGenClassExists(self):
""" Does the class exist? """
self.assert_(self.test is not None)
def testMyMethodExists(self):
""" Does MyMethod() exist?"""
result = self.test.myMethod()
self.assert_(result is not None)
在这两种情况下,如果类不存在,Python 就会直接报错。测试根本无法执行到验证的步骤。有没有更好的方法来实现这个呢?
5 个回答
如何检查一个方法是否存在于测试驱动开发(TDD)中?
这个问题标记为Python,但测试驱动开发在很多地方都适用。所以这里有一个基本的PHP示例...
class DatabaseTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
// if the class is not existing, one would skip the method tests
if (!class_exists('DatabaseHelper', false)) {
$this->markTestSkipped(
'DatabaseHelper class not available. Skipping all method tests.'
);
}
// subject under test
$database = new Database;
// i wouldn't go so far, as to test the methods of the class, anyway..
if(!is_callable(array($database, 'myMethod'))) {
$this->markTestSkipped(
'DatabaseHelper class does not contain method myMethod. '.
'Skipping all method tests.'
);
}
// this is very often used: if an PHP extension is not available
if (!extension_loaded('mysqli')) {
$this->markTestSkipped(
'The MySQLi extension is not available.'
);
}
}
public function testConnection()
{
// do Db thing ...
// assert method of a class
$this->assertTrue(
method_exists('DatabaseHelper', 'myHelperFunction'),
'Class DatabaseHelper does not have method myHelperFunction'
);
}
}
在PHP中使用的函数
- 类:
class_exists()
- 方法:
method_exists()
- 或者更好用的is_callable()
- 扩展:
extension_loaded()
你也可以使用Reflection
来检查类和函数/方法是否存在。下面这个方法是一个很常用的辅助函数,因为它可以同时检查方法和函数。
/**
* Assert that a class has a method
*
* @param string $class name of the class
* @param string $method name of the searched method
* @throws ReflectionException if $class don't exist
* @throws PHPUnit_Framework_ExpectationFailedException if a method isn't found
*/
function assertMethodExist($class, $method) {
$oReflectionClass = new ReflectionClass($class);
assertThat("method exist", true, $oReflectionClass->hasMethod($method));
}
在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,尤其是当我们刚开始学习编程的时候。
比如说,有人可能在使用某个特定的功能时,发现它的表现和预期不一样。这种情况很常见,尤其是在我们还不太熟悉某些概念或用法的时候。
在这种情况下,查看其他人的经验和解决方案就显得特别重要。很多时候,其他程序员会在网上分享他们遇到的问题和解决办法,这样我们就可以从中学习,避免走弯路。
总之,遇到问题时,不要气馁,去寻找答案和帮助是很正常的。编程的学习过程就是不断解决问题和积累经验的过程。
def testMyMethodExists(self):
""" Does MyMethod() exist?"""
self.assertTrue(hasattr(self.test, 'myMethod'))
unittest的文档里有一个例子,展示了如何使用assertRaises
这个功能:
import random
import unittest
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.seq = range(10)
def test_shuffle(self):
# make sure the shuffled sequence does not lose any elements
random.shuffle(self.seq)
self.seq.sort()
self.assertEqual(self.seq, range(10))
# should raise an exception for an immutable sequence
self.assertRaises(TypeError, random.shuffle, (1,2,3))
def test_choice(self):
element = random.choice(self.seq)
self.assertTrue(element in self.seq)
def test_sample(self):
with self.assertRaises(ValueError):
random.sample(self.seq, 20)
for element in random.sample(self.seq, 5):
self.assertTrue(element in self.seq)
if __name__ == '__main__':
unittest.main()
在这个例子中,有一个不知名的方法会引发一个AttributeError(属性错误),也许在assertRaises的部分来捕捉这个错误是一种方法?
要检查一个方法是否存在,可以使用 hasattr
,就像下面的例子所示:
class A(object):
def MethodInA(self):
pass
print hasattr(A, 'MethodInA')
print hasattr(A, 'RandomMethodNameNotInA')
运行后会得到这样的结果:
True
False
这个方法同样适用于类或者在模块中定义的方法。所以如果你想检查的类是在一个模块里写的,你也可以用同样的方法,比如:
import logging
print hasattr(logging, "LogRecord")
print hasattr(logging, "LogRecords")
类型的存在性
有异常的情况
如果一个类没有定义,试图使用它会抛出一个非常具体的错误。解决这个问题的一种方法是在使用这个类的地方(比如在setUp
中)捕获这个错误,然后立即失败。
def setUp(self):
try:
self.test = RandomGenClass()
except NameError as e:
pass # fail appropriately here.
要注意,这样做可能会掩盖一些错误的原因。例如,如果RandomGenClass.__init__
抛出了一个NameError
。所以在你的情况下,你可能需要更仔细地查看抛出的错误,以确保是"RandomGenClass"
没有定义,而不是其他更深层次的名称。
使用globals()
也许更好的方法是查看globals()
返回的字典,找出你想使用的类的名称。不过我个人觉得这种方法有点麻烦,更容易出问题。不过它没有掩盖其他错误的问题。
if not 'RandomGenClass' in globals():
pass # fail appropriately
使用hasattr
如果这些类存在于其他模块中(可能是,但不一定),我们可以像测试方法一样,在模块对象上使用hasattr
。这可能是最干净的方式。
import some_module
if not hasattr(some_module, 'ClassName'):
pass # fail appropriately
根据类的来源,你可能实际上可以更早捕获到它。如果你从定义类的地方导入类,你可以明确地导入所有类,并在类未定义时查找ImportError
。
方法的存在性
至于方法的测试,这部分很简单。一旦你知道类存在并且你有了它的实例,你可以使用hasattr
来判断某个名称是否在这个对象中定义。
if hasattr(self.test, 'method_name'):
result = self.test.method_name()
当然,你也可以几乎以完全相同的方式来测试类的存在性:直接去做,如果出错就捕获这个错误。同样,这需要某种验证,以确保你捕获的属性错误确实是你要找的那个。
try:
result = self.test.myMethod()
except AttributeError as e:
pass # fail appropriately