Test framework code - mikec964/chelmbigstock GitHub Wiki

The best explanation I've found for this is on StackOverFlow. It's flippin' genius.

Our code is set up like this:

/league
    /data
    /league
        __init__.py       # makes league a package
        match.py          # this is a module
    /test
        __init__.py       # makes test a package
        test_match.py

The challenge is to enable the code in test_match.py to be able to call methods in match.py.

The code in test_match.py will import match.py as a module. Therefore, you must:

  • Include __init__.py in the directory to make the directory into a package
  • Test names must be separated by an underscore, not a dash. Really.

Sample Test Program

file: test_stock.py

#!/usr/bin/env python3

import unittest

# These three lines enable you to run this from within the Tests directory
import os
import sys
sys.path.append(os.path.abspath('..'))

import league.match as match


class Test_read_players(unittest.TestCase):
    def test_loaded_some_players(self):
        players = []
        players = match.read_players()
        self.assertNotEqual(players, [])


class Test_match_players(unittest.TestCase):
    def test_matched_players(self):
        pass

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

You can run this test by executing it directly:

$ cd league/test
$ python3 -m unittest test_match  # leave off the .py extension

You can run all tests in this directory with:

$ cd league/league
$ python -m unittest discover

You can go up a level and run all the tests with the same command:

$ cd league
$ python -m unittest discover

Note This requires:

  • The test directory is named 'test' (not tests)
  • The test modules are named test*.py
  • The test modules use underscores, not dashes

I prefer a tests directory and to name the tests something_tests.py so it is easier to read the list in the directory.

$ cd league
$ python -m unittest discover -s tests -p '*tests.py'

I've created some aliases in .bashrc:

alias pytest='python -m unittest'
alias pytests='python -m unittest discover -s tests -p "*tests.py"'
alias py3test='python3 -m unittest'
alias py3tests='python3 -m unittest discover -s tests -p "*tests.py"'

Sample Program

If the program method or function reads data from a file, then when you import that method from your test program, it may not be able to find the file. Here's another solution from StackOverflow

WRONG:

    filepath = '../data/players.txt'
    with open('filepath', newline='') as csvfile:
            player_reader = csv.reader(csvfile, delimiter=' ')

The code below solves two problems:

  • It ensures the path to the data directory and file are relative to the module, not the calling program
  • It uses 'join' instead of '/', so the program works across Windows, Linux, and Mac OS.

RIGHT:

    datadir = 'data'
    filename = 'players.csv'
    # Use dirname(__file__) so this runs even when called from ../tests
    filepath = os.path.join(os.path.dirname(__file__), os.pardir, datadir, filename)

    with open(filepath, newline='') as csvfile:
            player_reader = csv.reader(csvfile, delimiter=' ')
#!/usr/bin/env python3

import os
import sys
import csv


def read_players():
    # read ../data/players.csv
    datadir = 'data'
    filename = 'players.csv'
    # Use dirname(__file__) so this runs even when called from ./tests
    filepath = os.path.join(os.path.dirname(__file__), os.pardir, datadir, filename)
    players = []

    with open(filepath, newline='') as csvfile:
            player_reader = csv.reader(csvfile, delimiter=' ')
            for row in player_reader:
                players.append(row)
    return players


def match_players():
    # create combinations
    pass


def print_matches():
    pass


if __name__ == "__main__":
    read_players()
    match_players()
    print_matches()