In this serial, I write about what I learned about Python over the weekend.
This week, I talked about (1) what is different between
static method and
class method, and (2) testing in python.
@staticmethod and @classmethod
When programming with python, you will see @staticmethod and @classmethod. What is the different?
Both @staticmethod and @classmethod are like static methods in Java.
They are a function (method) of a class.
For example, if you have a class name
A, which define a method
method_1 is static,
you can call this method without creating an instance of
>>> class A(object): class_var =  @staticmethod def static_method_1(): A.class_var.add(10) print A.class_var print "static method 1" @classmethod def class_method_1(): """ This will make an error when you run like TypeError: class_method_1() takes no arguments (1 given) """ print "class method 1" @classmethod def class_method_2(klass): """ This is fine """ print klass.A print "class method 2" >>>> A.static_method_1()  static method 1 >>>> A.class_method_1() TypeError: class_method_1() takes no arguments (1 given) >>>> A.class_method_2  class method 2
The only different between
must have first argument which is the class itself!
Test framework with python
nose is a test framework written in python
$ sudo pip install nose
When working with our company project, I have to work with it. Here is test case template was used
import unittest def setup() pass def teardown() pass class ModuleWantToTest(object): def test_function1(self): pass def test_function2(self): pass
Next, you will want to test like this:
$ nose test_file.py
Note that: two functions
teardown of a module will run before and after every class test cases.
If you want to make
teardown for every method in class, you must name it like
and your TestSuiteClass must be an inheritance from
import unittest import nose a =  def setup(): """ This method will run before any class Test """ with open('test_log', 'w') as f: f.write("setup module\n") a.extend([10, 20, 30]) def teardown(): """ If setup was run successful This method will will run after class Test """ with open('test_log', 'a') as f: f.write("teardown module %s\n" % a) for i in xrange(0, len(a)): a.pop() class SampleTestModule(unittest.TestCase): b =  @classmethod def setup_class(klass): """ This method will run before any method Test of SampleTestModule """ with open('test_log', 'a') as f: f.write("setup class\n") klass.b.extend([10, 20]) pass @classmethod def teardown_class(klass): """ This method will run after test and setup_class was run sucessful """ with open('test_log', 'a') as f: f.write("teardown class\n") klass.b.pop() klass.b.pop() a.pop() pass def setUp(self): with open('test_log', 'a') as f: f.write("setup method\n") self.b.extend([40, 50]) def tearDown(self): with open('test_log', 'a') as f: f.write("teardown method\n") self.b.pop() self.b.pop() def test_simple(self): assert len(a) == 3 assert a == [10, 20, 30] assert len(self.b) == 4 assert self.b == [10, 20, 40, 50] def test_simple2(self): assert len(a) == 3 assert a == [10, 20, 30] # change a a.append(1) # because teardow will call after test_simple, # and setup_class re-run before test_simple2 # so now b == [10, 20, 40, 50] assert len(self.b) == 4 assert self.b == [10, 20, 40, 50] class TestClass2(unittest.TestCase): def test_method(self): print a assert len(a) == 3 assert a == [10, 20, 30]
Run this code, and check the log file we will see:
$> python test_module.py $> cat test_log setup module setup class setup method teardown method setup method teardown method teardown class teardown module [10, 20, 30]
setup function of a module will run first, after that is
And with every test cases,
setUp function will be called at the beginning, after that, the real test case will be called.
tearDown function will be called regardless of the result of the test case.
NOTE again 2 functions must be
tearDown (it is camelCase but snake_case as PEP8 suggested)
But when in your test module, you want to import some other module, how you can do it?
Remember that, when you using
nose test_file.py, the environment of python is the path of
nose (which can get by
To solve it, you will want to add path of library to python path
Currently, I found 2 options:
- Export to environment variable
$ export PYTHONPATH=path__to__library
Every time you run the test on another bash shell, you must retype this command.
- You do not need to retype every time you run on another bash shell. You add it on directly on you test file by the below snippet
import os import sys library__path = path__to__library if library_path is not in sys.path: sys.path.insert(library_path, 0)
Most of the time, you want to structure your project folder like that:
project_name/ src/ test/
So you will want to add
src directory in python path:
current_path = os.path.dirname(__file__) src_path = os.path.join(curent_path, '..', 'src') if src_path not in sys.path: sys.path.insert(src_path, 0)
But it still got some annoying because the code to add
src path must be provided in every test modules.
The better solution should have a script name
test which include
And this script has options run all test modules or single test module.