Python Unittest, Inheritance, and Member Variable Propagation - python

I'm using Python 2.6. Let's say I have 2 classes:
class BaseTest(unittest.TestCase):
def test_a(self):
print 'test_a'
self.random_variable = random_string()
print self.random_variable
class SubTest1(BaseTest):
def test_b(self):
print 'test_b'
print self.random_variable
Where random_string() returns a randomly generated 20 character string.
I'd like to be able to access self.random_variable in SubTest1.test_b. Right now, self.random_variable in test_b is undefined.
When BaseTest runs, it would have its own unique random string, but when SubTest1 runs, it would have the same string generated in BaseTest. The output for all of this would ideally look something like this:
test_a
dgkwgmhkiszvmlhceved
test_a
akvjkskdmhfygsysgjci
test_b
akvjkskdmhfygsysgjci
Is this possible?

One of the principles of unit testing is that every test should be isolated from, and independent of, every other test. If you have test work that you want done in more than one test, then put it in a helper function, and call that function from the tests:
class MyTests(unittest.TestCase):
def do_common_stuff(self):
self.random_variable = random_string()
#... do more stuff you want in more than one test ...
def test_a(self):
self.do_common_stuff()
def test_b(self):
self.do_common_stuff()
#... do more stuff ...

Yes, you can define the variable in the setUp method which runs before each test case (so that's then different for each test):
class BaseTest(unittest.TestCase):
def setUp(self):
self.random_variable = random_string()
def test_a(self):
print 'test_a'
print self.random_variable
If you want it to be the same you'll need to use setUpClass:
class BaseTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
self.random_variable = random_string()
def test_a(self):
print 'test_a'
print self.random_variable
Note that marking setUpClass with #classmethod is important as it turns the method from a regular method into a class method (which receives the class rather than the instance as first argument).

Related

Listing all references in a python method

I have classes like these
class Test:
def __str__(self):
return "Test"
class Test1(Test):
def __str__(self):
return "Test1"
class Test2(Test):
def __str__(self):
return "Test2"
class Runner:
pass
class Runner1(Runner):
def run(self):
print("I'm a method, doing this and that")
print(f"And I use {Test1()}")
class Runner2(Runner):
def func2(self):
print("I'm a method, doing this and that")
test = Test2()
print(f"And I use {test}")
and I would like to discover all Runner classes, which use Test instances, like this:
for klass, func, ref in get_all_references(Runner):
if isinstance(ref, Test):
print(f"{klass.__name}.{func.__name} uses Test!")
That is, I'm looking for the get_all_references method, which returns all referenced objects of any classes of type Runner (and their methods), which I can inspect for class type/inheritance.
The motivation behind this is to discover all places (class/method names) where instances of Test are used.
I think part of the problem is solved by static analyzers/doc creators/cross reference builders, but I couldn't find any which could be used to get this information via an API.
i think gc module has several useful functions in that matter, but it sounds like gc.get_referrers() is what you need.

Python unittest skip test for only one subclass

Let's say I have my unittest set up like this:
import unittest
class BaseTest(object):
def setup(self):
self.foo = None
def test_something(self):
self.assertTrue(self.foo.something())
def test_another(self):
self.assertTrue(self.foo.another())
def test_a_third_thing(self):
self.assertTrue(self.foo.a_third_thing())
class TestA(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooA()
class TestB(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooB()
class TestC(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooC()
Now let's say FooC doesn't have a_third_thing implemented yet, and I want to skip test_a_third_thing for ONLY the TestC class. Is there some way I can use the #unittest.skipif decorator to do this? Or some other handy way to skip this test for only this class?
Python 2.7, in case it matters
You may not need to "skip" the test. One simple approach is to override the base test with a dummy.
class TestC(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooC()
def test_a_third_thing(self):
"""Override the assertions of the base test."""
pass
You cannot use #unittest.skipif here because it is evaluated during module, and the check needed should be run during runtime.
To achieve desired result your test_a_third_thing in base class should look like this:
class BaseTest(unittest.TestCase):
def test_a_third_thing(self):
if not getattr(self.foo, "a_third_thing", None):
self.skipTest(self.foo.__class__.__name__ + ' has no a_third_thing, skip')
else:
self.assertTrue(self.foo.a_third_thing())
Also fix typos in your example setup to setUp. Remove 'unittest.TestCase' from inheritance list of test classes and add to base class.

Are unittest attributes mutable in Python?

Suppose I have this integration test
class TestClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.key = '123'
def test_01_create_acc(self):
user = create_account(...)
self.key = user.key
def test_02_check_account(self):
user = check_account(..)
self.assertEqual(self.key, user.key)
It looks like the attribute self.key is not mutable. It stays with the old value from setUpClass. But isn't setUpClass only called once?
The account function creates a key randomly for security reason, so I am not allowed to pass in my secret key. It returns the key, so I need to modify that attribute. Can I?
It looks like each test_ case is isolated.
my_gloabl = None
def setUpClass(cls):
cls.key = my_global
If I change my_global in test1, test2 will get None.
The class is set up only once. But each test method is actually called from a different instance of that test.
You can demonstrate this using the id function, which will return a different number for each object:
import unittest
class TestClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
print "setup"
def test_01_create_acc(self):
print id(self)
def test_02_check_account(self):
print id(self)
unittest.main()
On my computer, this printed:
setup
4300479824
.4300479888
Note how the setup method was called only once, but the id of the instance for test1 and test2 are different.

How to access the parent class during initialisation in python?

How do I find out which class I am initialising a decorator in? It makes sense that I wouldn't be able to find this out as the decorator is not yet bound to the class, but is there a way of getting round this?
class A(object):
def dec(f):
# I am in class 'A'
def func(cls):
f(cls)
return func
#dec
def test(self):
pass
I need to know which class I am (indicated by the commented line).
I don't think this is possible. At the very moment when you define test, the class doesn't exist yet.
When Python encounters
class A(object):
it creates a new namespace in which it runs all code that it finds in the class definition (including the definition of test() and the call to the decorator), and when it's done, it creates a new class object and puts everything into this class that was left in the namespace after the code was executed.
So when the decorator is called, it doesn't know anything yet. At this moment, test is just a function.
I don't get the question.
>>> class A(object):
def dec(f):
def func(cls):
print cls
return func
#dec
def test(self):
pass
>>> a=A()
>>> a.test()
<__main__.A object at 0x00C56330>
>>>
The argument (cls) is the class, A.
As Nadia pointed out you will need to be more specific. Python does not allow this kind of things, which means that what you are trying to do is probably something wrong.
In the meantime, here is my contribution: a little story about a sailor and a frog. (use a constructor after the class initialization)
class Cruise(object):
def arewelostyet(self):
print 'Young sailor: I think I am lost, help me :s'
instance = Cruise()
instance.arewelostyet()
def whereami(lostfunc):
"""
decorator
"""
def decorated(*args, **kwargs):
lostfunc(*args, **kwargs)
print 'Frog: Crôak! thou art sailing in class', lostfunc.im_class.__name__
# don't forget to write name and doc
decorated.func_name = lostfunc.func_name
decorated.func_doc = lostfunc.func_name
return decorated
print '[i]A frog pops out of nowhere[/i]'
# decorate the method:
Cruise.arewelostyet = whereami(Cruise.arewelostyet)
instance.arewelostyet()

Overriding a static method in python

Referring to the first answer about python's bound and unbound methods here, I have a question:
class Test:
def method_one(self):
print "Called method_one"
#staticmethod
def method_two():
print "Called method_two"
#staticmethod
def method_three():
Test.method_two()
class T2(Test):
#staticmethod
def method_two():
print "T2"
a_test = Test()
a_test.method_one()
a_test.method_two()
a_test.method_three()
b_test = T2()
b_test.method_three()
produces output:
Called method_one
Called method_two
Called method_two
Called method_two
Is there a way to override a static method in python?
I expected b_test.method_three() to print "T2", but it doesn't (prints "Called method_two" instead).
In the form that you are using there, you are explicitly specifying what class's static method_two to call. If method_three was a classmethod, and you called cls.method_two, you would get the results that you wanted:
class Test:
def method_one(self):
print "Called method_one"
#staticmethod
def method_two():
print "Called method_two"
#classmethod
def method_three(cls):
cls.method_two()
class T2(Test):
#staticmethod
def method_two():
print "T2"
a_test = Test()
a_test.method_one() # -> Called method_one
a_test.method_two() # -> Called method_two
a_test.method_three() # -> Called method_two
b_test = T2()
b_test.method_three() # -> T2
Test.method_two() # -> Called method_two
T2.method_three() # -> T2
The behavior you see is the expected behavior. Static methods are... static. When you call method_three() defined in Test it will certainly call method_two() defined by Test.
As for how to "get around" this proper behavior...
The very best way is to make methods virtual when you want virtual behavior. If you're stuck with some library code with a static method that you wish were virtual then you might look deeper to see if there's a reason or if it's just an oversight.
Otherwise, you can define a new method_three() in T2 that calls T2.method_two().
Additionally, if you want to call the "virtual static" function without an instance, you could proceed like so:
Declare the function in the base class non-static like so:
class Base:
def my_fun(self):
print('my_fun base')
class Derived(Base):
def my_fun(self):
print('my_fun derived')
Call it by passing the class type, which is not an instance, like so:
Derived.my_fun(Derived)
Note, this is useful if you have a variable "class_type", which is only known during run time.

Categories

Resources