python-crash-course-book/chap11_testing.md

4.7 KiB

Chapter 11. Testing Your Code

Learn how to test code using Python's unittest module.

Testing a Function

Function to be tested as shown below.

def get_formatted_name(first, last):
    """Generate a neatly formatted full name."""
    full_name = f"{first} {last}"
    return full_name.title()

A script that should use get_formatted_name

from name_function import get_formatted_name

print("Enter 'q' at any time to quit.")
while True:
    first = input("\nPlease give me a first name: ")
    if first == 'q':
        break
    last = input("Please give me a last name: ")
    if last == 'q':
        break

    formatted_name = get_formatted_name(first, last)
    print(f"\tNeatly formatted name: {formatted_name}.")

To make sure get_formatted_name function properly, using unittest module of Python

import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    """Test for name_function.py"""

    def test_first_last_name(self):
        """Do names like 'Janis Joplin' work?"""
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')

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

Key points:

  • Import unittest module as shown
  • Import function to be tested
  • Here, unittest's most useful feature assert is used. assertEqual can compare two objects
  • __name__ is a special variable, which is set when the program is executed. If the file is being run as the main program, the value of __name__ is set to '__main__'

Result of running this test:

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

OK
  • First dot represent the single test passed.

A Failing Test

Failure case returns

F
======================================================================
FAIL: test_first_last_name (__main__.NamesTestCase)
Do names like 'Janis Joplin' work?
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_name_function.py", line 10, in test_first_last_name
    self.assertEqual(formatted_name, 'Janis Joplins')
AssertionError: 'Janis Joplin' != 'Janis Joplins'
- Janis Joplin
+ Janis Joplins
?             +


----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

Highlight:

  • FAIL: test_first_last_name tell's where the error coming from.

Fix them

If employing TDD, we can first create test case, then develop code to be test against.

Testing a Class

e.g. above shown how to write test case for single function, we also need to write test for class.

A Variety of Assert Methods

Python unittest module provide various assert methods in unittest.TestCase class.

List of available assert methods

Method Use
assertEqual(a,b) Verify a == b
assertNotEqual(a,b) Verify that a != b
assertTrue(x) Verify that x is True
assertFalse(x) Verify that x is False
assertIn(item, list) Verify that item is in list
assertNotIn(item, list) Verrify that item is not in list

A Class to Test

  • class to be tested in survey.py have class AnonymousSurvey
class AnonymousSurvey:
    """Collect anonymous answers to a survey questions"""

    def __init__(self, question):
        """Store a question, and prepare to store response."""
        self.question = question
        self.responses = []

    def show_question(self):
        """Show the survey question"""
        print(self.question)

    def store_response(self, new_response):
        """Store a single response to the survey"""
        self.responses.append(new_response)

    def show_results(self):
        """Show all the responses that have been given"""
        print("Survey results:")
        for response in self.responses:
            print(f"- {response}")
  • script to use AnonymousSurvey language_survey.py
from survey import AnonymousSurvey

# Define a question, and make a survey.
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)

# Show the questions, and store responses to the question
my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
    response = input("Language: ")
    if response == 'q':
        break
    my_survey.store_response(response)

# Show the survey results
print("\nThank you to everyone who participate in the survey")
my_survey.show_results()

If we want to