Building a Python Boilerplate Function with Unit Testing
When it comes to programming, we often find ourselves writing the same code snippets over and over again. These repetitive pieces of code are known as “boilerplate.” In this mini project, we’ll explore the boilerplate concept by creating a Python function step by step. Along the way, we’ll also implement unit tests to ensure the reliability of our code.
The Goal
Our objective is to create a Python function calculate()
that takes a list of nine digits as input, converts it into a 3x3 NumPy array, and returns a dictionary containing the mean, variance, standard deviation, max, min, and sum along both axes and for the flattened matrix.
The returned dictionary should follow this format:
{
'mean': [axis1, axis2, flattened],
'variance': [axis1, axis2, flattened],
'standard deviation': [axis1, axis2, flattened],
'max': [axis1, axis2, flattened],
'min': [axis1, axis2, flattened],
'sum': [axis1, axis2, flattened]
}
Additionally, we’ll handle input validation. If a list containing fewer or more than nine elements is passed into the function, it will raise a ValueError
exception with the message: "List must contain nine numbers."
Section 1: Creating the Boilerplate Function
What is a Boilerplate Code?
A boilerplate code refers to repetitive and standard sections of code that are used in multiple places within a program. In our case, it’s a function that calculates statistics from a 3x3 matrix.
Step-by-Step Implementation
We’ll create the calculate()
function in a new python file and let’s call it mean_var_std.py
, which starts by converting the input list into a 3x3 NumPy array. Then, it calculates the required statistics using NumPy functions. Here's a breakdown:
import numpy as np
def calculate(numbers):
# Raise a ValueError if the input list doesn't contain exactly nine elements.
if len(numbers) != 9:
raise ValueError("List must contain nine numbers")
# Convert the input list into a 3x3 NumPy array
matrix = np.array(numbers).reshape(3, 3)
# Calculate statistics
mean = [list(matrix.mean(axis=0)), list(matrix.mean(axis=1)), matrix.mean()]
variance = [list(matrix.var(axis=0)), list(matrix.var(axis=1)), matrix.var()]
std_deviation = [list(matrix.std(axis=0)), list(matrix.std(axis=1)), matrix.std()]
max_val = [list(matrix.max(axis=0)), list(matrix.max(axis=1)), matrix.max()]
min_val = [list(matrix.min(axis=0)), list(matrix.min(axis=1)), matrix.min()]
sum_val = [list(matrix.sum(axis=0)), list(matrix.sum(axis=1)), matrix.sum()]
# Create and return the result dictionary
result = {
'mean': mean,
'variance': variance,
'standard deviation': std_deviation,
'max': max_val,
'min': min_val,
'sum': sum_val
}
return result
Handling Invalid Inputs
Input validation is crucial to ensure the function works correctly. We raise a ValueError
if the input list doesn't contain exactly nine elements.
Returning Results
The function returns the calculated statistics in a dictionary with specified keys and lists.
Section 2: Unit Testing for Code Reliability
Introduction to Unit Testing
Unit testing is a software testing technique in which individual components (functions or methods) of a program are tested in isolation to ensure that they work correctly as expected.
Writing Test Cases
To verify the correctness of our calculate
function, we write unit tests using the unittest
module. Unittest module is a built-in Python library that can be used for writing and running unit test cases. Each test case checks specific scenarios to ensure that the function works reliably.
Let’s write the below code in a new Python script and call it test_module.py
First, import the unittest
and mean_var_std
module.
import unittest
import mean_var_std
Next, define your test cases by creating classes that inherit from unittest.TestCase
. Each test case class contains test methods that use various assertion methods provided by unittest
to check the behavior of your code.
class UnitTests(unittest.TestCase):
def test_calculate(self):
actual = mean_var_std.calculate([2,6,2,8,4,0,1,5,7])
expected = {'mean': [[3.6666666666666665, 5.0, 3.0], [3.3333333333333335, 4.0, 4.333333333333333], 3.888888888888889], 'variance': [[9.555555555555557, 0.6666666666666666, 8.666666666666666], [3.555555555555556, 10.666666666666666, 6.222222222222221], 6.987654320987654], 'standard deviation': [[3.091206165165235, 0.816496580927726, 2.943920288775949], [1.8856180831641267, 3.265986323710904, 2.494438257849294], 2.6434171674156266], 'max': [[8, 6, 7], [6, 8, 7], 8], 'min': [[1, 4, 0], [2, 0, 1], 0], 'sum': [[11, 15, 9], [10, 12, 13], 35]}
self.assertAlmostEqual(actual, expected, "Expected different output when calling 'calculate()' with '[2,6,2,8,4,0,1,5,7]'")
def test_calculate2(self):
actual = mean_var_std.calculate([9,1,5,3,3,3,2,9,0])
expected = {'mean': [[4.666666666666667, 4.333333333333333, 2.6666666666666665], [5.0, 3.0, 3.6666666666666665], 3.888888888888889], 'variance': [[9.555555555555555, 11.555555555555557, 4.222222222222222], [10.666666666666666, 0.0, 14.888888888888891], 9.209876543209875], 'standard deviation': [[3.0912061651652345, 3.39934634239519, 2.0548046676563256], [3.265986323710904, 0.0, 3.8586123009300755], 3.0347778408328137], 'max': [[9, 9, 5], [9, 3, 9], 9], 'min': [[2, 1, 0], [1, 3, 0], 0], 'sum': [[14, 13, 8], [15, 9, 11], 35]}
self.assertAlmostEqual(actual, expected, "Expected different output when calling 'calculate()' with '[9,1,5,3,3,3,2,9,0]'")
def test_calculate_with_few_digits(self):
self.assertRaisesRegex(ValueError, "List must contain nine numbers.", mean_var_std.calculate, [2,6,2,8,4,0,1,])
if __name__ == "__main__":
unittest.main()
The if __name__ == "__main__":
block checks whether the script is being run directly (as opposed to being imported as a module). If it's being run directly, it calls unittest.main()
. This is where the main
function from unittest
comes into play. It discovers and runs the test cases defined in your script.
Unit tests cover various scenarios, including valid inputs and invalid inputs. They help us catch potential issues early in the development process.
Using the Boilerplate Function and Running Unit Tests
Now that we’ve created our calculate
function in mean_var_std.py
and written unit tests in test_module.py
, let's see it in action. Create a main.py
file where we will use our boilerplate function and run test cases.
Using the calculate
Function
First, you’ll need to import the mean_var_std
module that contains our boilerplate function. Then, you can call the calculate
function with a list of nine digits. Here's how you can do it:
import mean_var_std
# Call the calculate function with a list of nine digits
result = mean_var_std.calculate([0,1,2,3,4,5,6,7,8])
# Print the result
print(result)
This code imports the mean_var_std
module, calls the calculate
function with the input list [0,1,2,3,4,5,6,7,8]
, and prints the result. You should see a dictionary containing various statistics, including mean, variance, standard deviation, max, min, and sum.
Running Unit Tests
To ensure the correctness and reliability of our function, and run the unit tests we’ve written using the unittest
module, you can use the following code:
from unittest import main
# Run unit tests automatically
main(module='test_module', exit=False)
The from unittest import main
statement is typically used in test scripts created with the unittest
framework to allow the test script to be executed as a standalone program. Here's what it does:
Imports the
unittest
Module: Thefrom unittest import main
statement imports themain
function from theunittest
module. Thismain
function is used to run the test cases defined in your test script. In our case it istest_module.py
Allows Standalone Execution: By including
from unittest import main
in your test script, you make it possible to execute the test script directly from the command line. Without this import, you would need to run your tests through a test runner, such asunittest
's built-in test runner or a test runner provided by a test framework.
This code imports the main
function from unittest
and runs the unit tests defined in the test_module.py
script. If all tests pass successfully, you'll see messages indicating that the tests ran successfully. If any tests fail, you'll be alerted to potential issues in your code.
By combining these steps, you can both use the calculate
function in your projects and verify its accuracy through unit testing, ensuring that your code works reliably and consistently.
Conclusion
Congratulations on completing this mini project where we’ve built a Python boilerplate function, step by step, while focusing on input validation and unit testing. Writing clean, tested code is crucial for ensuring code reliability and preventing bugs. We encourage you to try out the code on platforms like Replit to see your function in action
By following these practices, you’re not only building a useful function but also adopting good software development practices that will serve you well in your coding journey.
To deepen your understanding, here are some additional resources:
NumPy Documentation: Dive deeper into NumPy, a powerful library for numerical computing in Python.
Python Unit Testing with unittest: Explore more about unit testing in Python using the
unittest
framework.
Happy coding! 🤗
Subscribe to my newsletter
Read articles from Ananya Gupta directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ananya Gupta
Ananya Gupta
🌼Hey there, I'm Ananya, a 22-year-old software developer with a passion for Python and front-end development. When I'm not crafting elegant code or writing technical articles, you can find me lost in the world of creativity, wielding a pencil and sketchbook. My pretty brown eyes may catch your attention, but it's my mind that's brimming with thoughts waiting to be explored. Let's embark on a journey of code and creativity together! ✨