Modules and PyTest¶

🎨 Modules¶

Any .py file is a Python module.

A module serves as a collection of variables and functions that can be used by other modules.

Modules that are executed directly are also called scripts.

In [ ]:
%%file math_stuff.py

def add_three_numbers(a, b, c):
    return a + b + c

def multiply_three_numbers(a, b, c):
    return a * b * c

def average_three_numbers(a, b, c):
    return a + b + c / 3
In [ ]:
%%file demo.py
from math_stuff import add_three_numbers, multiply_three_numbers

a = 7
b = 2
c = 3

print(add_three_numbers(a, b, c))
print(multiply_three_numbers(a, b, c))
In [ ]:
%%file another_demo.py
import math_stuff

a = 3
b = 6
c = 8

print(math_stuff.add_three_numbers(a, b, c))
print(math_stuff.multiply_three_numbers(a, b, c))

math_stuff.py¶

demo.py¶

another_demo.py¶

In [ ]:
! python demo.py
In [ ]:
! python another_demo.py

Both demo.py and another_demo.py use the functions defined in math_stuff.py.

Often, modules that provide functions that are intended to be used by other scripts are called libraries.

🎨 PyTest¶

PyTest is a library we can use to test our code.

In [ ]:
%%file test_math_stuff.py
from math_stuff import add_three_numbers, multiply_three_numbers, average_three_numbers


def test_add_three_numbers():
    result = add_three_numbers(2, 3, 4)
    assert result == 9
    result = add_three_numbers(-1, 0, 2)
    assert result == 1
    
    
def test_multiply_three_numbers():
    result = multiply_three_numbers(2, 3, 4)
    assert result == 24
    result = multiply_three_numbers(1, 0, 2)
    assert result == 0
    
    
def test_multiply_three_numbers_with_negatives():
    assert multiply_three_numbers(-1, -2, -3) == -6
    
    
def test_average_three_numbers():
    assert average_three_numbers(1, 2, 3) == 2

test_math_stuff.py¶

NOTES

When writing tests:

  • The name of the file with the tests starts with test_
    • Typically the rest of the name corresponds to the module being tested
    • So, the tests for math_stuff.py would be in a file named test_math_stuff.py
  • The name of each test function starts with test_
    • The rest of the name typically corresponds to the function being tested
    • So, the tests for add_three_numbers would be tested by a function named test_add_three_numbers
    • You might also include something about the specific case being tested, e.g. test_multiply_three_numbers_with_negatives
  • Use assert to test whether something you have tested matches your expectations
  • PyCharm automatically identifies tests.
    • Demonstrate how to run them
    • Go over test outputs
      • individual tests with output
      • observe the failed test (average_three_numbers)

👨🏾‍🎨 Write Some Tests¶

Our business-critical Python script isn't working correctly:

important_business.py

Write tests for the functions found in

list_tools.py

and fix the problem!

NOTES

  • Run important_business.py. It fails. We need better test coverage!
  • Create a file named test_list_tools.py
  • Add tests for each function in list_tools.py
  • only_evens has a bug.
    • Test for all even numbers
    • Test for all odd numbers
    • Test for a mix of even and odds
    • Test for 0 (should be treated as even)
  • twice_as_long
    • test on lengths as well as contents
    • test on a typical list
    • test on an empty list
  • sum_all
    • test on typical list
    • test on empty list (should return 0)
    • test on floats
    • test on negatives
In [ ]:
%%file list_tools.py

def only_evens(items):
    """Return a list containing only the even elements of the input list"""
    result = []
    for item in items:
        if item % 2 != 0:
            result.append(item)
    return result


def twice_as_long(items):
    """Return a list that is twice as long as the input: A, B, C => A, B, C, A, B, C"""
    result = []
    for item in items:
        result.append(item)
    for item in items:
        result.append(item)
    return result


def sum_all(numbers):
    """Sum all the numbers in a list"""
    result = 0
    for item in numbers:
        result = result + item
    return result
In [ ]:
%%file important_business.py

from list_tools import only_evens, twice_as_long, sum_all

numbers = [2, 0, 1, 3, 8, 4]

numbers = only_evens(numbers)
numbers = twice_as_long(numbers)
result = sum_all(numbers)

if result == 28:
    print("Success! 😊")
else:
    print("Fail. ☠️")

Tests¶

  • Help us demonstrate that individual pieces of our code are working
  • Help us quickly identify parts of our code that are not working
  • Are most helpful when you write them as you go, instead of all at the very end
  • Help us design good functions
    • Write functions that have a clear, simple purpose that would be easy to test