Understanding Unit Testing in Python: Testing Laundry Price Calculations

What is Unit Testing?

In the world of software development, ensuring that your code works correctly is crucial. This is where unit testing comes into play. Unit testing is a type of software testing where individual units or components of the software are tested. The primary goal is to validate that each unit of the software performs as expected.

Unit testing helps developers identify and fix bugs early in the development process, which can save time and reduce costs. Additionally, it makes the codebase more maintainable and reliable, leading to higher-quality software.

In this article, we'll explore the basics of unit testing in Python using the unittest library. To make it more practical, we'll walk through a real-world example: testing the calculation of laundry prices. This project involves creating a function to calculate the total cost of laundry based on the weight of the clothes and the price per kilogram. By the end of this article, you’ll have a solid understanding of how to implement and run unit tests in Python, ensuring your functions work correctly and efficiently.

About Laundry Price Calculations

In our daily lives, many of us rely on laundry services to save time and effort. Typically, the cost of these services is calculated based on the weight of the clothes and a fixed price per kilogram. To automate and simplify this calculation, we can write a Python function that takes the weight of the laundry and the price per kilogram as inputs and returns the total cost.

This project aims to create a reliable function for calculating laundry prices and ensure its accuracy through unit testing. By doing so, we can avoid potential errors and guarantee consistent results, which is especially important for businesses relying on precise cost calculations.

Business Rules

As a business in general, of course, laundry seeks profit. In this project, we will define some business rules to get closer to what happens in the real world.

  1. Minimum order is 3kg.

  2. Orders under 3kg will be counted as a minimum order (3kg).

  3. Only Complete Express and Speedy Express packages are available for orders under or equal to 1 day.

There will be 4 packages:

Package NamePrice/KgProcessing Time (Day)
Folded Dry CleaningRp70003
Folded Dry CleaningRp85002
Iron Dry CleaningRp100003
Iron Dry CleaningRp120002
Complete ExpressRp150001
Speedy ExpressRp250000.2083 (5 Hours)

No need to be confused for packages with the same name, they are still the same package, it's just that the price and duration of work are different.

The Logic

The logic is quite simple, the program calculates the total price to be paid based on the quantity of laundry (kg) and the price of the laundry package.

Example

Package NameQuantity (Kg)Processing Time (Day)Total Price (Rp)
Folded Dry Cleaning4234000
Complete Express2130000
Folded Dry Cleaning2321000
Iron Dry Cleaning5450000
Speedy Express30.208375000
Iron Dry Cleaning4248000

Now it's Time to Code

  1. Setting Up the Environment

    • Ensure you have Python installed from python.org.

    • Use an IDE like PyCharm or VS Code for coding.

  2. hargaBayar.py

    Create a file with name hargaBayar.py.

    Here is the code for the class that calculates laundry prices:

     """
     Description
     mko = Minimum Kilogram
     prk = Price Per Kilogram
     dy = Day
     tpy = Total Pay
     pkg = Package
     desc = Package Name
    
     Package options:
     1. Folded Dry Cleaning
     2. Iron Dry Cleaning
     3. Complete Express
     4. Speedy Express
     """
    
     class calcPayment:
         def __init__(self, pkg, ko, dy):
             self.pkg = pkg
             self.ko = ko
             self.dy = dy
             self.desc = None
    
         def countTotal(self):
             mko = 3.00
             prk = 0.00
             tpy = 0.00
    
             ## Package calculations (1) Folded Dry Cleaning
             if self.pkg == 1:
                 self.desc = "Folded Dry Cleaning"
                 prk = 7000.00
    
                 if self.dy < 3:
                     if self.dy > 1:
                         prk = 8500.00
                         if self.ko < mko:
                             self.ko = mko
                     elif self.dy < 2:
                         raise ValueError("Folded Dry Cleaning at the earliest 2 days")
                 else:
                     if self.ko <= 3:
                         self.ko = mko
    
                 tpy = prk * self.ko
    
             ## Package calculations (2) Iron Dry Cleaning
             elif self.pkg == 2:
                 self.desc = "Iron Dry Cleaning"
                 prk = 10000.00
    
                 if self.dy < 3:
                     if self.dy > 1:
                         prk = 12000.00
                         if self.ko < mko:
                             self.ko = mko
                     elif self.dy < 2:
                         raise ValueError("Iron Dry Cleaning at the earliest 2 days")
                 else:
                     if self.ko <= 3:
                         self.ko = mko
    
                 tpy = prk * self.ko
    
             ## Package calculations (3) Complete Express in 1 day
             elif self.pkg == 3:
                 self.desc = "Complete Express"
                 self.dy = 1
                 prk = 15000.00
    
                 if self.ko < mko:
                     self.ko = mko
    
                 tpy = prk * self.ko
    
             ## Package calculations (4) Speedy Express in 5 hours
             elif self.pkg == 4:
                 self.desc = "Speedy Express"
                 prk = 25000.00
                 self.dy = 0.2083
    
                 tpy = prk * self.ko
    
             print("Note:")
             print("1. Orders under 3 kilograms will be counted as a minimum order (3kg).")
             print(
                 "2. Only Complete Express and Speedy Express packages are available for orders under or equal to 1 day."
             )
             print("\nHere is Your Payment")
             print(f"Package: {self.desc}")
             print(f"Quantity: {self.ko} Kilogram")
             print(f"Processing time: {self.dy} Day")
             print(f"Total Payment: Rp{tpy}")
             print("\nThank You for Ordering")
             return (
                 tpy  # You can change this to a blank string when you not doing unit testing
             )
    
     # Test the calculation
     order = calcPayment(4, 4, 1)  # calcPayment(package, quantity, processing time(day))
     print(order.countTotal())
    
  3. Writing Unit Testing

    To ensure our calcPayment class works correctly, we need to write unit tests using the unittest library. Here's how to do it:

    Create file with name test_hitung_harga.py

     import unittest
     import sys
    
     # Adjust path according the file location
     sys.path.append(
         "Your\Path" # Example "C:\Coding\Unit Testing"
     )
    
     from laundryCode.hitungHarga import calcPayment
    
     class TestCalculations(unittest.TestCase):
    
         def setUp(self):
             self.tp1 = calcPayment(1, 2, 5)
             self.tp2 = calcPayment(2, 5, 3)
             self.tp3 = calcPayment(3, 5, 1)
             self.tp4 = calcPayment(4, 4, 1)
    
         def test_calculation_FDC(self):
             self.assertEqual(self.tp1.countTotal(), 21000.0, "Incorrect calculation")
    
         def test_calculation_IDC(self):
             self.assertEqual(self.tp2.countTotal(), 50000.0, "Incorrect calculation")
    
         def test_calculation_CEP(self):
             self.assertEqual(self.tp3.countTotal(), 75000.0, "Incorrect calculation")
    
         def test_calculation_SEP(self):
             self.assertEqual(self.tp4.countTotal(), 100000.0, "Incorrect calculation")
    
     if __name__ == "__main__":
         unittest.main(buffer=True)  # Ignore text from class
    

    This test suite covers various scenarios for each package type, ensuring that the calcPayment class handles different inputs correctly.

  4. Run the Program

    Run the program with your terminal or IDE.

    Well, LGTM!

  5. Source Code

    You can see the source code here.

Conclusion

Unit testing is an essential practice in software development. It helps ensure the accuracy and reliability of your code by identifying bugs early in the development process. By implementing unit tests for our calcPayment class, we can confidently calculate laundry prices and handle various input scenarios without errors.

I hope this guide has provided you with a clear understanding of how to write and run unit tests in Python. Happy coding!


👋 Hello, I’m Abdiel, 1st Year Informatics Student, Programmer, and Freelancer.

🥰 If you liked this article, consider sharing it.

🔗 Portfolio | GitHub | LinkedIn

1
Subscribe to my newsletter

Read articles from Muhammad Abdiel Al Hafiz directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Muhammad Abdiel Al Hafiz
Muhammad Abdiel Al Hafiz

Balancing my role as an IT Fullstack intern at a financial startup with my studies as a second-year Informatics student, I'm passionate about Machine Learning and AI. Skilled in Python and ML, I'm dedicated to turning data-driven insights into real-world applications. Always eager to engage with like-minded professionals and collaborate on breakthrough initiatives in the tech world.