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=2argument inunittest.main()is used to display the name of each test and its result (okorfail). - Test cases are defined inside the
TestMainclass, and each test case must be written as a method that starts with the wordtest. - 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.