Skip to content

Testing

Testing in Python

Testing ensures that our code works as expected and helps catch errors early.

Test file is used before releasing the main file to the world


Code Quality Tools

  • pylint → checks code for errors and enforces coding standards.
  • pyflakes → detects errors without enforcing style.
  • autopep8 → automatically formats code according to PEP8 guidelines.

Unit Testing with unittest

Python has a built-in module called unittest for writing and running tests.

Basic Setup

import unittest

class TestExercise(unittest.TestCase):
    def test_input(self):
        pass

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

Testing a Function

Example: Testing a Guessing Function

main file


import random

print('GUESS A NUMBER')

def run_guess(guess, answer):
    if 0 < guess < 11:
            if guess is answer:
                print('You are a genius')
                return True
    else:
        print('try again')
        return False

if __name__ == '__main__':
    answer = random.randint(1, 10)
    print(answer)
    while True:
        try:
            guess = int(input('guess a numbers 1-10: '))
            if run_guess(guess, answer):
                break
        except ValueError:
            print('you did something wrong')
            continue

test file

import unittest
import Exercise

class TestExercise(unittest.TestCase):
    def test_input(self):
        result = Exercise.run_guess(5, 5)
        self.assertTrue(result)
    # this test case when the guess is correct, which is 5, and the expected result is True

    def test_input2(self):
        result = Exercise.run_guess(0, 5)
        self.assertFalse(result)
    # this test case is testing the case when the guess is 0, which is not a valid guess, and the expected result is False

    def test_input3(self):
        result = Exercise.run_guess(11, 5)
        self.assertFalse(result)

    def test_input4(self):
        result = Exercise.run_guess(5, '5')
        self.assertFalse(result)

if __name__ == '__main__':
    unittest.main(verbosity=2)
Example: Testing a Function

main file

def do_stuff(num=0):
    try:
        if num:
            return int(num) + 5
        else:
            raise ValueError("No parameter provided")
    except ValueError as err:
        return err

test file

import unittest
import main

class TestMain(unittest.TestCase):
    def setUp(self):
        print('About to run a function')

    def test_do_stuff(self):
        '''Hiii'''
        test_parameter = 1
        result = main.do_stuff(test_parameter)
        self.assertEqual(result, 6)

    def test_do_stuff2(self):
        test_parameter = 'woahh'
        result = main.do_stuff(test_parameter)
        self.assertIsInstance(result, ValueError)

    def test_do_stuff3(self):
        test_parameter = None
        result = main.do_stuff(test_parameter)
        self.assertEqual(str(result), 'No parameter provided')

    def tearDown(self):
        print('Cleaning up...')     #setup and teardown are used to run code before and after each test case.


if __name__ == '__main__':
    unittest.main(verbosity=2)
  • setUp() → runs before each test case.

  • tearDown() → runs after each test case.

  • verbosity=2 → shows detailed test results.

Run tests with:

python -m unittest test_main.py
Understanding Unit Test Details
  • The verbosity=2 argument in unittest.main() is used to display the name of each test and its result (ok or fail).
  • Test cases are defined inside the TestMain class, and each test case must be written as a method that starts with the word test.
  • You can add comments or docstrings to test methods to explain:
  • What the test case is checking.
  • What the expected result should be.

Why Testing Matters
  • Tests are used to check our code as thoroughly as possible.
  • Even with a simple function, writing multiple test cases helps uncover small issues that might otherwise go unnoticed.
  • Tests catch small issues early and improve code reliability and quality of our code.