Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write Python unit tests for scripts in my bin directory

The Python unittest module seems to assume a directory structure for a project in which there's a project root level directory with the source code and tests under that directory.

I would like, however, to write Python scripts in my ~/bin directory and tests for it in another directory (say, ~/dev/tests). Is there a way for me to run the unit tests using the command line interface without setting my PYTHONPATH environment variable and creating __init__.py files and whatnot?

Here's a simple example demonstrating what I want:

~/bin/candy:

#!/usr/bin/env python

def candy():
    return "candy"

if __name__ == '__main__':
    print candy()

~/dev/tests/test_candy.py:

#!/usr/bin/env python

import unittest
import candy

class CandyTestCase(unittest.TestCase):

    def testCandy(self):
        candyOutput = candy.candy()

        assert candyOutput == "candy"

I notice that everything can be done conveniently if:

  • The two files are named with py extensions (candy.py and test_candy.py)
  • The two files are in the same directory
  • The test is run with the following in the directory of the tests: $ python -m unittest test_candy

Can I run python with the unittest module to do the following without setting anything in my environment explicitly:

  • My file under test does not have the py extension (just ~/candy).
  • I don't care if test_candy has py as an extension or not.
  • I want candy and test_candy.py to not share a common root (other than my home directory).

If that's not possible with a simple invocation of python -m unittest, what is the most simple way to accomplish this?

like image 664
firebush Avatar asked Nov 02 '15 01:11

firebush


People also ask

Where do I put unit tests in Python?

Tests are put in files of the form test_*. py or *_test.py , and are usually placed in a directory called tests/ in a package's root.

How do I run a Python test from the command line?

You can invoke testing through the Python interpreter from the command line: python -m pytest [...] This is almost equivalent to invoking the command line script pytest [...] directly, except that calling via python will also add the current directory to sys.


Video Answer


1 Answers

This is candy executable (no change):

➜ cat ~/bin/candy

#!/usr/bin/env python    
def candy():
  return "candy"

if __name__ == '__main__':
  print candy()

and this is ~/dev/tests/test_candy.py (changed):

➜ cat ~/dev/tests/test_candy.py

#!/usr/bin/env python

import imp
import unittest

from os.path import expanduser, join

# use expanduser to locate its home dir and join bin and candy module paths
candy_module_path =  join(expanduser("~"), "bin", "candy")

# load the module without .py extension
candy = imp.load_source("candy", candy_module_path)


class CandyTestCase(unittest.TestCase):

    def testCandy(self):
        candyOutput = candy.candy()

        assert candyOutput == "candy"

What changed?

  • We added imp.load_source to import ~/bin/candy (a module without *.py extension)

  • We added provision to locate home directory mention i.e. ~ using expanduser

  • We are using os.path.join to join the paths for ~/bin/candy

Now you can run the tests with discover option of unittest module.

Check python -m unittest --help for more details.

Excerpts below

-s directory Directory to start discovery ('.' default)

-p pattern Pattern to match test files ('test*.py' default)

➜ python -m unittest discover -s ~/bin/ -p 'test*' -v ~/dev/tests
testCandy (test_candy.CandyTestCase) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
like image 181
Navid Avatar answered Oct 20 '22 06:10

Navid