# parent
class Parent(unittest.TestCase):
#classemthod
def setUpClass(cls):
cls.attr1 = '123'
# real test
class TestMe(Parent):
#classmethod
def setUpClass(cls):
cls.attr2 = '456'
super(Parent, cls).setUpClass()
But if we try to access attr1 from TestMe, the interpreter will say the attribute does not exist.
I also tried to add __init__ in TestMe but didn't help.
Any idea why I can't do this?
Thanks!
You are not using super as you intended. You are asking for the superclass of Parent, so you end up calling unittest.setUpClass, which of course does nothing.
Change it to
#classmethod
def setUpClass(cls):
super(TestMe, cls).setUpClass()
Related
As can be seen in the following example, I've defined a BaseClass for all tests, each test case class inherits the base class.
Both classes needs to perform a one time initialization, when test_vehicles.py is executed, I need to make sure that setUpClass of the base class is invoked as well, not sure how to achieve that where #classmethod is in play.
# base.py
import unittest
class BaseClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
# initialize stuff
cls.app = app
# test_vehicles.py
class VehiclesTestCase(BaseClass):
#classmethod
def setUpClass(cls):
# initialize stuff
cls.vehicle_id = '123'
def test_get_vehicle(self):
resp = self.app.get(self.vehicle_id)
self.assertEqual(resp, True)
if __name__ == '__main__':
unittest.main()
Similar question Using super with a class method. More information yoou can get also from https://docs.python.org/3/library/functions.html#super.
Solution: use super function and bound to the class
# test_vehicles.py
class VehiclesTestCase(BaseClass):
#classmethod
def setUpClass(cls):
super(VehiclesTestCase, cls).setUpClass()
cls.vehicle_id = '123'
if __name__ == '__main__':
unittest.main()
You can use the super method in the inherited classes' setUpClass to access the setUpClass of BaseClass:
super().setUpClass()
If you don't want to call super in each child class, just create an abstract method in BaseClass and call it in setUpClass of BaseClass. VehiclesTestCase now has to implement this abstract method:
class BaseClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
# initialize stuff
cls.app = app
#classmethod
def _setUpChild(cls):
raise NotImplementedError
class VehiclesTestCase(BaseClass):
#classmethod
def _setUpChild(cls):
# initialize stuff
cls.vehicle_id = '123'
def test_get_vehicle(self):
resp = self.app.get(self.vehicle_id)
self.assertEqual(resp, True)
I would also recommend that BaseClass is not a TestCase if it cannot run by itself. It would always show up in your test report although it has no tests. You can instead use multi-inheritance:
class BaseClass:
# Stuff
class VehiclesTestCase(BaseClass, unittest.TestCase):
# Stuff
The order of inheritance is important. Method lookup is done from left to right. This means that BaseClass.setUpClass overrides the setUpClass of TestCase.
I need to deliver something like this in my program
class the_class_name(Parent):
the_attribute = self.parent_class_method()
#the parent class method will return a value
#but I cannot use self here since there's no self
How can I carry this out? Is there any other alternative that can do the job for me?
I have tried using __init__ like this:
def __init__(self):
Parent.__init__(self)
self.attribute = self.the_method()
But then I have problem creating the object, it won't receive any parameters that the Parent class normally receives anymore
Sounds like you are looking for __init__:
class TheClassName(Parent):
def __init__(self):
# Set attribute to the result of the parent method
self.attribute = super(TheClassName, self).the_method()
EDIT
If your parent class has parameters in it's own __init__ function, include them in the child class:
class Parent(object):
def __init__(self, foo, bar):
...
#classmethod
def the_method(cls):
...
class TheClassName(Parent):
def __init__(self, foo, bar):
super(TheClassName, self).__init__(foo, bar)
self.attribute = super(TheClassName, self).the_method()
I don't quite understand why you don't just call the parent method on your child object when you need the value though.
There is no self at that point of the creation of the subclass, nor is there an instance of the Parent class. That means the only Parent class methods you could call would have to be either static or class methods.
To demonstrate:
class Parent(object):
#staticmethod
def static_method():
return 42
#classmethod
def class_method(cls):
return 43
class TheClassName(Parent):
the_attribute = Parent.static_method()
another_attribute = Parent.class_method()
print(TheClassName.the_attribute) # -> 42
print(TheClassName.another_attribute) # -> 43
You must use class methods, declared with the #classmethod decorator, or a #staticmethod. The #classmethod decorator is preferable so that inheritance is handled correctly, i.e. the method is invoked on the derived class (a bit of a technicality, if you are still learning this).
class Alpha(object):
#classmethod
def method1(cls):
return 'method1 has been called on {}'.format(cls)
class Beta(Alpha):
def __init__(self):
self.myattr = Beta.method1()
print(Beta().myattr)
method1 has been called on class <'__main__.Beta'>
Use
super(ClassName, self).methodname(arg)
inside a method
def child_method(self, arg):
super(ClassName, self).methodname(arg)
You cannot use self outside a method.
Let's say I have this parent class:
class BaseTestCase(unittest.TestCase):
#classmethod
def setUpClass(cls):
# I want to assign the name of the class that called
# the super class in a variable.
cls.child_class_name = ??
# Do some more stuff...
And I have this class that inherits from the BaseTestCase class above:
class MyTestCase(BaseTestCase):
#classmethod
def setUpClass(cls):
# Call SetUpClass from parent (BaseTestCase)
super(cls, cls).setUpClass()
# Do more stuff...
Since many classes can inherit from the same parent class. How can I know the name of the class that invoked the parent class in a given time?
I hope my question make sense. :S
cls.__name__ is always the name of the current class, because cls is bound the actual class object on which the class method was called.
In other words, cls is not a reference to the class on which the method is defined.
Note that you should not use super(cls, cls)! That'll lead to infinite recursion if you were to create a derived class from MyTestCase! Use the actual class, always:
class MyTestCase(BaseTestCase):
#classmethod
def setUpClass(cls):
# Call SetUpClass from parent (BaseTestCase)
super(MyTestCase, cls).setUpClass()
# Do more stuff...
Demo:
>>> class Foo(object):
... #classmethod
... def spam(cls):
... print(cls.__name__)
...
>>> class Bar(Foo):
... #classmethod
... def spam(cls):
... super(Bar, cls).spam()
...
>>> Bar.spam()
Bar
>>> Foo.spam()
Foo
I'm trying to inherit attributes from a super class but they are not being initialized correctly:
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
super(Thing, self).__init__()
print self.attribute1
This throws an error since attribute1 is not an attribute of OtherThing, even though Thing.attribute1 exists. I thought this was the correct way to inherit and extend a super class. Am I doing something wrong? I don't want to create an instance of Thing and use its attributes, I need it to inherit this for simplicity.
You have to give, as argument, the class name (where it is being called) to super():
super(OtherThing, self).__init__()
According to Python docs:
... super can be used to refer to parent classes without naming them
explicitly, thus making the code more maintainable.
so you are not supposed to give the parent class.
See this example from Python docs too:
class C(B):
def method(self, arg):
super(C, self).method(arg)
Python3 makes this easy:
#!/usr/local/cpython-3.3/bin/python
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
#super(Thing, self).__init__()
super().__init__()
print(self.attribute1)
def main():
otherthing = OtherThing()
main()
I'm trying to access a parent member variable from an extended class. But running the following code...
class Mother(object):
def __init__(self):
self._haircolor = "Brown"
class Child(Mother):
def __init__(self):
Mother.__init__(self)
def print_haircolor(self):
print Mother._haircolor
c = Child()
c.print_haircolor()
Gets me this error:
AttributeError: type object 'Mother' has no attribute '_haircolor'
What am I doing wrong?
You're mixing up class and instance attributes.
print self._haircolor
You want the instance attribute, not the class attribute, so you should use self._haircolor.
Also, you really should use super in the __init__ in case you decide to change your inheritance to Father or something.
class Child(Mother):
def __init__(self):
super(Child, self).__init__()
def print_haircolor(self):
print self._haircolor