我如何在python 2.6中测试抽象方法

时间:2014-01-25 14:14:08

标签: python unit-testing exception abstract-class python-2.6

我有一个抽象类:

import abc


class Hello(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def add(self, foo):
        pass

    @abc.abstractmethod
    def remove(self, foo):
        pass

我正在使用abc来做抽象方法,所以,当我这样做时:

hello = Hello()

并引发此错误:TypeError: Can't instantiate abstract class Hello with abstract methods add, remove

所以我可以用以下方法测试这种类型的错误:

self.assertRaises(Exception, Hello)  # but this only test the constructor and i can't get the 100% of code coverage. I need call the add method and the remove method

额外的问题:任何人都知道如何在python 2.6中断言消息异常? (你不能使用with:来提出断言。)

如何测试这种抽象方法以获得100%的代码覆盖率?

3 个答案:

答案 0 :(得分:6)

如何创建抽象方法的文档字符串而不是使用https://stackoverflow.com/a/19275908/469992中提到的pass呢?它还可以用于提供有关该方法在子类中应该做什么的一些信息。

abstract.py,

from abc import ABCMeta, abstractmethod                                            

class A(object):                                                                   
    __metaclass__ = ABCMeta                                                        

    @abstractmethod                                                                
    def some_method(self):                                                         
        "This method should ..."                                                   

class B(A):                                                                        
    def some_method(self):                                                         
        return 1

test_abstract.py,

import unittest                                                                    
import abstract                                                                    

class TestB(unittest.TestCase):                                                    
    def test(self):                                                                
        self.assertEqual(abstract.B().some_method(), 1)   

然后,使用python 2.6.8,nosetests --with-xcoverage输出,

.
Name       Stmts   Miss  Cover   Missing
----------------------------------------
abstract       7      0   100%   
----------------------------------------------------------------------
Ran 1 test in 0.004s  

答案 1 :(得分:0)

如果要检查类dict中的键:

>>> Hello.__dict__.has_key('__abstractmethods__')
True
>>> Hello.__dict__.has_key('__metaclass__')
True
>>>

您可以确保将Hello.__abstractmethods__中定义的所有方法覆盖到您的子类中。

>>> Hello.__abstractmethods__
frozenset(['add', 'remove'])
>>>

如果您错过了在子类中重新定义这些方法的任何方法,您仍会因错过的方法而获得TypeError:

TypeError: Can't instantiate abstract class Abs_Hello with abstract methods remove

或者像这样测试怎么样:

 def check_all(abstract, sub_class):
    abs_method = abstract.__abstractmethods__
    for m in abs_method:
        if not isinstance(m, sub_class):
            raise TypeError("%s is not defined in subclass %s" % (m, repr(sub_class)))

答案 2 :(得分:0)

你永远不应该实例化一个抽象类。您看到该错误的原因是设计原因。抽象方法在它们的子类中实现,因为它定义了类不同的行为。抽象类封装了这些子类之间共享的行为。

为了说明,你需要这样的东西:

class Language(Hello):

    def add(self, foo):
        self.baz.append(foo)

    def remove(self, foo):
        self.baz[foo] = None

注意Language如何从Hello继承。 所以你真的应该测试抽象类的子类的实例,而不是抽象类本身。