python testing + folder structure – import issues

19 01 2008
whenever i start coding something in python i use the following folder structure:

my_project
        ./foo
             ./__init__.py
             ./bar.py
        ./tests
             ./test_foo.py
             ./test_bar.py

but i used to get confused on how to organize the import(s) and when to use PYTHONPATH for my tests.

my requirements are:

  • i want to be able to run my tests both from my_project folder and from the tests folder
  • i don’t want to set the PYTHONPATH manually (and i don’t want to add my development path to PYTHONPATH.
  • i want to import the lib modules on the test on the same way i would import after the lib is deployed.

(yes i am lazy)

bar.py:

def dumb_true():
    return True

1st try

the code for test_bar.py should like something like this:

import unittest

from foo import bar

class TestBar(unittest.TestCase):
    def test_bar_true(self):
        self.assertTrue(bar.dumb_true())

if __name__ == '__main__':
    unittest.main()

the problem here is that you need to set the PYTHONPATH manually.

2nd try

the first thing that comes in my mind is to add ‘foo’ folder to PYTHONPATH on the test module

...
import sys,os
sys.path.insert(0,os.path.abspath(__file__+"/../.."))
from foo import bar
...

not bad. but you need to add this to every single test module. and hope that your folder structure wont change.

3rd try

i guess we need a smarter test runner (like nose).
get your code back to just:

...
from foo import bar
...

you can just run “nosetests” from the project folder (‘my_project’ in the example above) and it will just work.

the same doesn’t happen if run “nosetests” from the tests folder.

from nose homepage:
When nose imports a module, it adds that module’s directory to sys.path; when the module is inside of a package, like package.module, it will be loaded as package.module and the directory of package will be added to sys.path.

so the trick here is to make the tests folder a package (adding __init__.py to it). so in the tests folder you will find:

./tests
     ./__init__.py
     ./test_foo.py
     ./test_bar.py

now from the tests folder you can:

  1. execute all tests doing “nosetests”
  2. execute just one file “nosetests test_bar.py”
  3. check nose docs for more options

and you don’t have to worry about PYTHONPATH at all :)

more nose

nose also free you from all the unittest boilerplate code. the test file could be just:

from foo import bar

def test_bar_true():
    assert bar.dumb_true()

and thats it.

About these ads

Actions

Information

5 responses

25 02 2010
edulan

Great post! Just what I’m looking for.

24 03 2013
Rafael

Great post, man! I was tired of finding crappy responses on StackOverflow!

22 04 2013
Trenton

Holy smokes I’ve been trying to understand imports for days, if not weeks/months now… I finally understand it with your demonstration of how you solved your problem! thank you so much!

29 05 2013
Python Nose Import Error | BlogoSfera

[…] get the same error when I run from inside the tests/ directory. According to the documentation and an example I found, nose is supposed to add all parent packages to the path as well as the directory from […]

3 11 2013
Python Nose Import Error | Ask Programming & Technology

[…] get the same error when I run from inside the tests/ directory. According to the documentation and an example I found, nose is supposed to add all parent packages to the path as well as the directory from […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




Follow

Get every new post delivered to your Inbox.

%d bloggers like this: