如何检查TDD中是否存在方法?

时间:2014-03-08 17:52:20

标签: python unit-testing python-2.7

在严格的测试驱动开发方法中,每个步骤都需要事先进行测试。即使是一个阶级或其方法的存在 - 严格来说 - 在实际创建之前都要进行测试。

我在编写测试时遇到问题,看是否存在方法。

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就已经失败了。测试永远不会断言。有没有更好的方法来实现这一目标?

4 个答案:

答案 0 :(得分:5)

类型的存在

有例外

如果没有定义类,尝试使用它会抛出一个非常具体的错误,所以解决这个问题的一种方法是捕获该错误(可能在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

答案 1 :(得分:2)

documentation for 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子句的一部分来捕捉它是一种方法吗?

答案 2 :(得分:2)

检查方法是否存在可以使用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")

答案 3 :(得分:0)

  

如何检查TDD中是否存在方法?

问题被标记为Python,但TDD无处不在。所以这是一个基本的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来检查Class和Function / Method是否存在。 以下方法是一种非常常见的辅助函数,因为它适用于方法和函数。

/**
 * 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));
}