mercredi 27 août 2014

Where to put unit tests in Python

I use unittest in Python almost every time I have to write a piece of code (I'm into TDD thing, you know). I know it's old fashionned compared to py.test but I like it anyway.

My issue when I began with it was to choose the right place to put my tests in project's directory structure. Packages and modules system proposed by Python do not make it as flexible as Java or Ruby. Today, I know that the answer is to put them in a separate directory and use unittest CLI and auto discovery.

My workflow is to write a unittest module along with corresponding production module. I run unittest module at every change. What I have been doing since today is to store test modules in the same package than production modules. The benefits are that importing the tested module in unit tests is straight-forward and I can run the tests directly by executing test python file. The concern is that it really disturbs me to put the tests with the production code.

The solution I found primarily was to update Python path directly in test code. That's not elegant.

Bellow is what I'm doing now. I put prod code and test code in separate directories:

root/
    myapp/
        __init.py__
        mymodule.py
    test/
        __init.py__
        test_mymodule.py

Import section in test_mymodule.py looks like this:

    import unittest
    from myapp import MyClass

    class MyClassTest(unittest.TestCase):
        ...

I'm not able to run the test directly by launching test_mymodule anymore, but I can use unittest CLI from within the root directory:

# This will use auto discovery to run every test found in the directory
python -m unittest

# I can run only one test module
python -m unittest test.test_mymodule

# Or even a single test case in Python 3
python -m unittest test.test_mymodule.MyClassTest

This works in Python 3 (I currently use 3.4) but at least both first commands should work with Python 2.7.

The result is pretty acceptable to me. I hope it will be for you either!