Pyunit or Unitest
-
Used to test a unit of source code
Features:
1. PyUnit is very simple yet very flexible
2. Test report formats generated: XML, unittest xml reports
3. Supports fixtures, test cases, test suites and test runners for automation of testing
How Code is tested?
1. Create the class which need to be tested
2. Create seperate module(which import above class) & calls its functions for testing.
Examples
Ex1: Simple Test
# car.py # Class to test
class car:
name = ""
def set(self, name) -> bool():
self.name = name
return True
def get(self):
return self.name
if __name__ == '__main__':
c = car()
if c.set('BMW') == True:
print('car BMW has been added')
else:
print('car add failed')
print('car is ', c.get())
> python.exe .\car.py
car BMW has been added
car is "BMW"
# car_testing.py # Write the unittest module(which will test car class)
import unittest
import car as c # import the class which we want to test
class car_testing(unittest.TestCase): # This class should inherit unittest.TestCase
car = c.car() # Create object of car class
"""
Note unittest module executes the test functions in the order of their name
since we want our set() test to execute first, we have named our test case
functions as test_0_set() and test_1_get()
"""
def test_0_set(self): # Any method which starts with ``test_`` will considered as a test case.
print ("\nStart set() test..")
self.car.set('Audi')
print("Finish set() test\n")
def test__1_get(self):
print("\nStart get() test..")
# 5. if 2 parameters does not match test case will fail
var = self.car.get()
print (var)
self.assertEqual(var, 'Audi')
print("Finish get() test\n")
if __name__ == '__main__':
unittest.main()
> python.exe .\car_testing.py
Start set() test..
Finish set() test
.
Start get() test..
Audi
Finish get() test
.
----------------------------------------------------------------------
Ran 2 tests in 0.009s
OK
Ex2: Writing Mock object
-
How it works?
1. We create mock object.
2. Assign mock object a function call which need to be mocked. For example:
requests.get(): We will mock this API, since this can take n/w delay which is not needed while testing
3. Write assert() and compare return value from mock.
// File to be tested
# weather.py
import requests
def get_weather(city):
response = requests.get(f"https://api.weather.com/{city}")
if response.status_code == 200:
return response.json()["weather"]
return None
// test module. This will test weather.get_weather()
import unittest
from unittest.mock import patch
from weather import get_weather
class TestWeather(unittest.TestCase):
"""
weather.requests.get = { status_code=200, json.return_value = {"weather": "Sunny"} }
mock object = mock_get = mock response
"""
# The @patch decorator is used to replace an object or function with a mock object during the test.
# This replaces weather.requests.get with a mock object(mock_get)
@patch("weather.requests.get")
def test_get_weather_success(self, mock_get):
mock_response = mock_get.return_value #Create a local reference to the mock object
mock_response.status_code = 200 # Setting values in the mock response
mock_response.json.return_value = {"weather": "Sunny"} # Setting values in the mock response
city = "NewYork"
result = get_weather(city) #Call the function to test
self.assertEqual(result, "Sunny") # Test. fail on 2 results are unequal
# Test. Ensures that requests.get was called exactly once with the expected URL
# If mock_get was never called or called multiple times, the test fails.
mock_get.assert_called_once_with(f"https://api.weather.com/{city}")
@patch("weather.requests.get")
def test_get_weather_failure(self, mock_get):
# Mock response with a failure status code
mock_response = mock_get.return_value
mock_response.status_code = 404
city = "InvalidCity"
result = get_weather(city)
# Assertions
self.assertIsNone(result)
mock_get.assert_called_once_with(f"https://api.weather.com/{city}")
if __name__ == "__main__":
unittest.main()
> python test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.003s
OK