Building a Python Boilerplate Function with Unit Testing

Ananya GuptaAnanya Gupta
6 min read

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_stdmodule.

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.pyand 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:

  1. Imports the unittest Module: The from unittest import main statement imports the main function from the unittest module. This main function is used to run the test cases defined in your test script. In our case it is test_module.py

  2. 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 as unittest'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:

Happy coding! 🤗

0
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! ✨