I have an abstract class:
import abc
class Hello(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def add(self, foo):
pass
@abc.abstractmethod
def remove(self, foo):
pass
I'm using abc for do abstract methods, so, when i do:
hello = Hello()
and this error is raised: TypeError: Can't instantiate abstract class Hello with abstract methods add, remove
So I can test this type error with:
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
Extra question: anybody knows how can i assert the message exception in python 2.6? (you can't use the with:
for raise assertions.)
How can i test this abstract methods for get the 100% of code coverage?
What about creating a doc string of the abstract method instead of using pass
as mentioned here, https://stackoverflow.com/a/19275908/469992 ? It can also be used to give some information about what the method is supposed to do in the sub classes.
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)
Then, using python 2.6.8, nosetests --with-xcoverage
outputs,
.
Name Stmts Miss Cover Missing
----------------------------------------
abstract 7 0 100%
----------------------------------------------------------------------
Ran 1 test in 0.004s
What about checking the key in class dict:
>>> Hello.__dict__.has_key('__abstractmethods__')
True
>>> Hello.__dict__.has_key('__metaclass__')
True
>>>
You can make sure to overide all the method defined inside Hello.__abstractmethods__
into your subclass.
>>> Hello.__abstractmethods__
frozenset(['add', 'remove'])
>>>
If you missed to re-defined any of those method in your sub-class, you will still getting TypeError for the missed methods:
TypeError: Can't instantiate abstract class Abs_Hello with abstract methods remove
OR how about testing like this :
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)))
You should never be instantiating an abstract class. The reason you are seeing that error is by design. Abstract methods are implemented in their sub-classes, because that defines the behavior where the classes are different. The abstract class encapsulates behavior that is shared between these sub-classes.
To illustrate, you want something like this:
class Language(Hello):
def add(self, foo):
self.baz.append(foo)
def remove(self, foo):
self.baz[foo] = None
Notice how Language
inherits from Hello
.
So really you're supposed to test an instance of a sub class of your abstract class, not the abstract class itself.