pytest: Different directories

This post describes a problem you may encounter when using pytest and the module and unit tests resided in different directories.

In this post I used Python 3.6.1 and VS Code 1.52.1 running on Windows 10. The module and the unit tests can be found on GitHub.

The code and the tests

fizz_buzz.py is a module which contains functions to solve the Fizzbuzz programming challenge.

"""
Program to showcase different ways to solve the FizzBuzz coding challenge. 
Each function will 
    Count from 1 - 100 inclusive     
    For numbers divisible by 3, Add to the list the string fizz
    For numbers divisible by 5, Add to the list the string buzz
    For numbers divisible by both 3 and 5, Add to a list the string fizzbuzz
    For all other numbers add the number to the list and return it to the caller    
"""


def fizz_buzz_using_boolean():
    """The results of the mod calculations are set to booleans
       which makes the if statements easier to understand"""
    fizz_buzz_list = []

    for x in range(1, 101):            

        fizz = x % 3 == 0 
        buzz = x % 5 == 0
        
        if fizz and buzz:            
            fizz_buzz_list.append('fizzbuzz')
            continue
        elif fizz:            
            fizz_buzz_list.append('fizz')
            continue
        elif buzz:            
            fizz_buzz_list.append('buzz')
            continue
        else:            
            fizz_buzz_list.append(x)            

    return fizz_buzz_list


def fizz_buzz_if_calc():
    """Fizzbuzz solution with the mod operator used within the 
       if statements"""
    fizz_buzz_list = []

    for x in range(1, 101):
        
        if x % 3 == 0 and x % 5 == 0:            
            fizz_buzz_list.append("fizzbuzz")
            continue
        elif x % 3 == 0:            
            fizz_buzz_list.append("fizz")
            continue
        elif x % 5 == 0:            
            fizz_buzz_list.append("buzz")
            continue        
        else:
            fizz_buzz_list.append(x)
    
    return fizz_buzz_list


if __name__ == "__main__":    

    fb_list_2 = fizz_buzz_using_boolean()
    print(fb_list_2)

    fb_list_1 = fizz_buzz_if_calc()
    print(fb_list_1)            

test_fizz_buzz.py contains the unit tests.

import pytest

from fizz_buzz import fizz_buzz_if_calc, fizz_buzz_using_boolean


@pytest.fixture
def expected_number_of_elements():
    """The fizzbuzz list will have 100 elements"""
    return 100


@pytest.fixture
def fizzbuzz_expected_answer():
    """A list of the fizzbuzz answers for 1 - 100"""
    fizz_buzz = [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz', 31, 32, 'fizz', 34, 'buzz', 'fizz', 37, 38, 'fizz', 'buzz', 41, 'fizz', 43, 44, 'fizzbuzz', 46, 47, 'fizz', 49, 'buzz', 'fizz', 52, 53, 'fizz', 'buzz', 56, 'fizz', 58, 59, 'fizzbuzz', 61, 62, 'fizz', 64, 'buzz', 'fizz', 67, 68, 'fizz', 'buzz', 71, 'fizz', 73, 74, 'fizzbuzz', 76, 77, 'fizz', 79, 'buzz', 'fizz', 82, 83, 'fizz', 'buzz', 86, 'fizz', 88, 89, 'fizzbuzz', 91, 92, 'fizz', 94, 'buzz', 'fizz', 97, 98, 'fizz', 'buzz']
    
    return fizz_buzz


def test_fizz_buzz_if_calc_has_100_elements(expected_number_of_elements):
    
    actual = fizz_buzz_if_calc()

    assert len(actual) == expected_number_of_elements


def test_fizz_buzz_using_boolean_has_100_elements(expected_number_of_elements):
    
    actual = fizz_buzz_using_boolean()
    
    assert len(actual) == expected_number_of_elements


def test_fizz_buzz_if_calc_has_correct_items(fizzbuzz_expected_answer):
    
    actual = fizz_buzz_if_calc()

    assert actual == fizzbuzz_expected_answer


def test_fizz_buzz_using_boolean_has_correct_items(fizzbuzz_expected_answer):
    
    actual = fizz_buzz_using_boolean()

    assert actual == fizzbuzz_expected_answer

When everything is in the same directory

Initially the directory structure for the application looked like this:

myapp   
   fizz_buzz.py
   test_fizz_buzz.py 
      

Using the test runner in VS Code, the unit tests ran successfully.

Changes to the directory structure

I wanted to change the directory structure and move the module and unit tests into their own directories. After making the changes, the directory structure looked like this:

myapp
   src
      fizz_buzz.py
   tests
      test_fizz_buzz.py 
      

Problems

Following the directory structure change, the tests had disappeared from the test runner within VS Code:

Opening the test_fizz_buzz.py file showed the error

"unable to import 'fizz_buzz' pylint(import-error) [3, 1]. 

The tests worked before the directory structure change which meant it was likely that Python could no longer find the fizz_buzz module.

Solution

The following changes were made to the import section of test_fizz_buzz.py.

import pytest

import sys
sys.path.insert(0, './src/')
from fizz_buzz import fizz_buzz_if_calc, fizz_buzz_using_boolean

On line 3 the sys module is imported, this module is then used on line 4 to add the src directory as a location for Python to check for the module.

With this change, the tests appear again in the test runner.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.