21

Sadly I observed that there are are too many ways to keep your unittest in Python and they are not usually well documented.

I am looking for an "ultimate" structure, one would accomplish most of the below requirements:

  • be discoverable by test frameworks, including:
    • pytest
    • nosetests
    • tox
  • the tests should be outside the module files and in another directory than the module itself (maintenance), probably in a tests/ directory at package level.
  • it should be possible to just execute a test file (the test must be able to know where is the module that is supposed to test)

Please provide a sample test file that does a fake test, specify filename and directory.

1
  • What is your question, really? Why don't you just use one of the frameworks and let everyone do as they like? Commented Oct 7, 2011 at 9:46

1 Answer 1

19

Here's the approach I've been using:

Directory structure

# All __init__.py files are empty in this example.
app
    package_a
        __init__.py
        module_a.py
    package_b
        __init__.py
        module_b.py
    test
        __init__.py
        test_app.py
    __init__.py
main.py

main.py

# This is the application's front-end.
#
# The import will succeed if Python can find the `app` package, which
# will occur if the parent directory of app/ is in sys.path, either 
# because the user is running the script from within that parect directory
# or because the user has included the parent directory in the PYTHONPATH
# environment variable.

from app.package_a.module_a import aaa
print aaa(123, 456)

module_a.py

# We can import a sibling module like this.
from app.package_b.module_b import bbb
def aaa(s, t):
    return '{0} {1}'.format(s, bbb(t))

# We can also run module_a.py directly, using Python's -m option, which
# allows you to run a module like a script.
#
#    python -m app.package_a.module_a
if __name__ == '__main__':
    print aaa(111, 222)
    print bbb(333)

module_b.py

def bbb(s):
    return s + 1

test_app.py

import unittest

# From the point of view of testing code, our working modules
# are siblings. Imports work accordingly, as seen in module_a.
from app.package_a.module_a import aaa
from app.package_a.module_a import bbb

class TestApp(unittest.TestCase):

    def test_aaa(self):
        self.assertEqual(aaa(77, 88), '77 89')

    def test_bbb(self):
        self.assertEqual(bbb(99), 100)

# Simiarly, we can run our test modules directly as scripts using the -m option,
# or using nose.
#
#    python -m app.test.test_app
#    nosetests app/test/test_app.py

if __name__ == '__main__':
    unittest.main()
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, for the example but I'm sure that if you will run test_app.py it will complain that is not able to find 'app'. Think that test must pass before the package is deployed to Python include path.
@sorin True, but you can get very close with the two examples provided at the end of my answer.
The whole point was to call the test frameworks without any parameters.
@sorin That works too, at least for nose. If you just run 'nosetests', all tests are executed. I guess I'm not understanding your goals, but good luck.
@Lee If you want to test the foo() function, the test method does not have to be named test_foo() -- it can be test_bar() or anything else. But if you want the test running framework (eg, unittest or nose or pytest) to discover your tests, you need to follow some general naming conventions (eg, start the method name with test_). I don't remember the exact rules, but they are easily searched for in the docs.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.