views:

2406

answers:

13

If you're writing a library, or an app, where do the unit test files go?

It's nice to separate the test files from the main app code, but it's awkward to put them into a "tests" subdirectory inside of the app root directory, because it makes it harder to import the modules that you'll be testing.

Is there a best practice here?

+8  A: 

I don't believe there is an established "best practice".

I put my tests in another directory outside of the app code. I then add the main app directory to sys.path (allowing you to import the modules from anywhere) in my test runner script (which does some other stuff as well) before running all the tests. This way I never have to remove the tests directory from the main code when I release it, saving me time and effort, if an ever so tiny amount.

dwestbrook
+7  A: 

A common practice is to put the tests directory in the same parent directory as your module/package. So if your module was called foo.py your directory layout would look like:

parent_dir/
  foo.py
  tests/

Of course there is no one way of doing it. You could also make a tests subdirectory and import the module using absolute import.

Wherever you put your tests, I would recommend you use nose to run them. Nose searches through your directories for tests. This way, you can put tests wherever they make the most sense organizationally.

Cristian
I'd like to do this but I can't make it work.To run the tests, I'm in the parent_dir, and type: "python tests\foo_test.py", and in foo_test.py: "from ..foo import this, that, theother" That fails with: "ValueError: Attempted relative import in non-package" Both parent_dir and tests have an __init__.py in them, so I'm not sure why they aren't packages. I suspect it's because the top-level script you run from the command line cannot be considered (part of) a package, even if it's in a dir with an __init__.py. So how do I run the tests? I'm working on Windows today, bless my cotton socks.
Tartley
The best way-- I've found-- to run unit tests is to install your library/program then run unit tests with nose. I would recommend virtualenv and virtualenvwrapper to make this a lot easier.
Cristian
@Tartley - you need a __init__.py file in your 'tests' directory for absolution imports to work. I have this method working with nose, so I'm not sure why you are having trouble.
Casey
Thanks Casey - but I do have an __init__.py file in all relevant directories. I don't know what I do wrong, but I have this problem on all my Python projects and I can't understand why nobody else does. Oh deary.
Tartley
One solution for my problem, with Python2.6 or newer, us to run the tests from the root of your project using:python -m project.package.tests.module_tests (instead of python project/package/tests/module_tests.py). This puts the test module's directory on the path, so the tests can then do a relative import to their parent directory to get the module-under-test.
Tartley
This arrangement is supported by http://guide.python-distribute.org/example.html
Craig McQueen
A: 

I've recently started to program in Python, so I've not really had chance to find out best practice yet. But, I've written a module that goes and finds all the tests and runs them.

So, I have:

app/
 appfile.py
test/
 appfileTest.py

I'll have to see how it goes as I progress to larger projects.

quamrana
+3  A: 

I use a tests/ directory, and then import the main application modules using relative imports. So in MyApp/tests/foo.py, there might be:

from .. import foo

to import the MyApp.foo module.

John Millikin
A: 

In C#, I've generally separated the tests into a separate assembly.

In Python -- so far -- I've tended to either write doctests, where the test is in the docstring of a function, or put them in the if __name__ == "__main__" block at the bottom of the module.

George V. Reilly
+3  A: 

For a file module.py, the unit test should normally be called module_test.py, following Pythonic naming conventions.

There are several commonly accepted places to put module_test.py:

  1. In the same directory as module.py.
  2. In ../tests/module_test.py (at the same level as the code directory).
  3. In tests/module_test.py (one level under the code directory).

I prefer #1 for its simplicity of finding the tests and importing them. Whatever build system you're using can easily be configured to run files ending in _test.

A: 

When writing a package called "foo", I will put unit tests into a separate package "foo_test". Modules and subpackages will then have the same name as the SUT package module. E.g. tests for a module foo.x.y are found in foo_test.x.y. The __init__.py files of each testing package then contain an AllTests suite that includes all test suites of the package. setuptools provides a convenient way to specify the main testing package, so that after "python setup.py develop" you can just use "python setup.py test" or "python setup.py test -s foo_test.x.SomeTestSuite" to the just a specific suite.

Sebastian Rittau
A: 

If the tests are simple, simply put them in the docstring -- most of the test frameworks for Python will be able to use that:

>>> import module
>>> module.method('test')
'testresult'

For other more involved tests, I'd put them either in ../tests/test_module.py or in tests/test_module.py.

+3  A: 

I also tend to put my unit tests in the file itself, as Jeremy Cantrell above notes, although I tend to not put the test function in the main body, but rather put everything in an

if __name__ == '__main__':
   do tests...

block. This ends up adding documentation to the file as 'example code' for how to use the python file you are testing.

I should add, I tend to write very tight modules/classes. If your modules require very large numbers of tests, you can put them in another, but even then, I'd still add:

if __name__ == '__main__':
   import tests.thisModule
   tests.thisModule.runtests

This lets anybody reading your source code know where to look for the test code.

Thomas Andrews
A: 

We use

app/src/code.py

app/testing/code_test.py

app/docs/..

In each test file we insert "../src/" in sys.path. It's not the nicest solution but works. I think it would be great if someone came up w/ something like maven in java that gives you standard conventions that just work, no matter what project you work on.

André
A: 

I prefer toplevel tests directory. This does mean imports become a little more difficult. For that I have two solutions:

1) Use setuptools. Then you can pass test_suite='tests.runalltests.suite' into setup(), and can run the tests simply: python setup.py test

2) Set PYTHONPATH when running the tests: PYTHONPATH=. python tests/runalltests.py

Here's how that stuff is supported by code in M2Crypto: http://svn.osafoundation.org/m2crypto/trunk/setup.py and http://svn.osafoundation.org/m2crypto/trunk/tests/alltests.py

If you prefer to run tests with nosetests you might need do something a little different.

A: 

We had the very same question when writing Pythoscope (http://pythoscope.org), which generates unit tests for Python programs. We polled people on the testing in python list before we chose a directory, there were many different opinions. In the end we chose to put a "tests" directory in the same directory as the source code. In that directory we generate a test file for each module in the parent directory.

Paul Hildebrandt
+1  A: 

How I do it...

Folder structure:

module/
    modulename/
        src/
            code.py
    tests/
    setup.py

Setup.py points to src/ as the location containing my modules scripts then i run:

setup.py develop

Which adds my module into site-packages, pointing to my working copy. To run my tests i use:

setup.py tests

Using whichever test runner I've configured.

gridzbi