How to Write Unit Tests in Python – with Example Test Code (2024)

/ #Python
How to Write Unit Tests in Python – with Example Test Code (1)
Damilola Oladele
How to Write Unit Tests in Python – with Example Test Code (2)

Unit testing is a software testing technique in which individual components or units of a software application are tested independently from the rest of the application.

In software development, it's beneficial to break your application into small, isolated units. This approach allows you to write independent tests to check all parts of your application, ensuring that they behave as expected. Also, if a test fails, you can easily isolate and troubleshoot the area of the code that has the bug without tampering with the rest of your application.

Python provides built-in support for unit testing through the unittest testing framework. There are also other third-party testing frameworks that you can use for your unit testing, such as pytest.

This article focuses on how to use the unittest framework to write tests for your Python applications and why developers often prefer it.

To get the best out of this article, you should have a basic understanding of the Python programming language.

Why Do Developers Prefer to Use unittest?

While there are many frameworks for unit testing in the Python ecosystem, many developers still prefer the built-in unittest due to its compelling advantages.

First, the unittest module is part of Python's standard library. This ensures immediate availability and compatibility across various environments without extra dependencies. The seamless integration with various environments makes it convenient for developers to use unittest without installing additional packages.

Second, as a long-standing framework within the Python ecosystem, unittest benefits from familiarity and longevity. Many developers are already used to its API and structure, making it a reliable choice for testing.

Third, most integrated development environments (IDEs) such as PyCharm offer built-in support for unittest. This improves developer productivity and streamlines the testing process, allowing for easier test management and execution.

Fourth, the framework has comprehensive and well-maintained documentation. This provides detailed guidance and examples, aiding developers in effectively using unittest for their testing needs.

Finally, many existing Python projects use unittest for testing, ensuring compatibility with legacy codebases. This widespread adoption allows developers to maintain and extend older projects without needing to introduce and adapt to a new testing framework.

How to Write Unit Tests with unittest

Unit testing with unittest involves creating test cases to verify the functionality of individual units of your code. Each test case is defined by subclassing unittest.TestCase. This allows you to inherit the several methods provided by the TestCase class.

Some of the methods provided by the TestCase class are assert methods. These assert methods allow you to check whether the actual result of a function or operation matches the expected result, or whether certain conditions are met. If an assertion fails, the test is marked as failed, and you will receive an error message.

See Classes and functions for detailed information about the different methods provided by the TestCase class.

Now, let's use two of the assert methods to write tests for a simple calculator program. First, create a new folder (directory), named unit-testing. Then, create a file named calculator.py within your unit-testing folder. Now, copy the following code into your calculator.py file:

def add(x, y): """add numbers""" return x + ydef subtract(x, y): """subtract numbers""" return x - ydef divide(x, y): """divide numbers""" return x / ydef multiply(x, y): """multiply numbers""" return x * y

Notice that instead of having your calculator program within a single function, we broke it into four independent functions (units). This is to ensure that each part of the program is independently tested. So if any of the units gives an error during testing, you can easily identify that unit and troubleshoot it without tampering with the other parts of your program.

As earlier mentioned, testing with unittest involves creating a subclass of the unittest.TestCase class and then defining methods within the subclass to test individual units of your program.

To show how this works, let's write a test for the add function in your calculator program. In your unit-testing folder, create a new file named test_calculator.py and then copy the following code into it:

import unittestimport calculatorclass TestCalculator(unittest.TestCase): def test_add(self): self.assertEqual(calculator.add(1, 2), 3) self.assertEqual(calculator.add(-1, 1), 0) self.assertEqual(calculator.add(-1, -1), -2) self.assertEqual(calculator.add(0, 0), 0)

In lines one and two of your code, you imported the unittest and your calculator modules. You then created a TestCalculator class, which inherits from the TestCase class.

In line five of your code, you defined a test_add method within your class. The method just like every instance methods in Python takes self as its first argument. Since self is a reference of the TestCalculator class, it can access the assertEqual method provided by the TestCase class, which TestCalculator inherits from.

The assertEqual method checks if two values are equal. It has the following syntax:

self.assertEqual(first, second, msg=None)

In the preceding syntax, first represents the value you want to test against the second value. msg is optional and it represents a custom message that you will receive if the assertion fails. If you don't provide a value for msg, you will receive a default message.

Now, let's use the explanation of the syntax to explain the use of assertEqual in your test_add method. In your first assertion, self.assertEqual(add(1, 2), 3) checks if the result of add(1, 2) is equal to 3. If the function returns 3, the test passes. Otherwise, it fails and outputs a message indicating the mismatch. This explanation is the same for the rest of your assertions.

Also, notice that you tested just representative values in your test_add method. This ensures that your test covers a wide range of possible inputs without redundant code. Here is a breakdown of the representative values in your test_add method:

  • The addition of two positive numbers (self.assertEqual(calculator.add(1, 2), 3)).
  • The addition of a negative number and a positive number (self.assertEqual(calculator.add(-1, 1), 0)).
  • The addition of two negative numbers (self.assertEqual(calculator.add(-1, -1), -2)).
  • The addition of two zeros (self.assertEqual(calculator.add(0, 0), 0)).

Now, to run your test, navigate to the unit-testing directory in your terminal and run the following command:

python -m unittest test_calculator.py

Running the preceding command will give you the following message in your terminal:

.----------------------------------------------------------------------Ran 1 test in 0.000sOK

The output indicates that you ran a single test and it was successful.

To ensure that your test is working as expected, you go back to your calculator.py file and change the addition (+) operator in your add function to subtraction (-), like this:

def add(x, y): """add numbers""" return x - y

Once you've made the changes, running your test again will raise an AssertionError showing that your test failed:

Traceback (most recent call last): File ".../test_calculator.py", line 6, in test_add self.assertEqual(calculator.add(1, 2), 3)AssertionError: -1 != 3----------------------------------------------------------------------Ran 1 test in 0.000s

You may be wondering why you have to include the unittest module in your command instead of running python test_calculator.py. That's because you are yet to make your test_calculator.py file a standalone script. So running python test_calculator.py won't give you any output.

To make your test_calculator.py executable as a standalone script, you need to add the following to the bottom of your test_calculator.py file:

if __name__ == "__main__": unittest.main()

Also, the unittest module requires that you start the name of your test methods with the word test, otherwise, your test won't run as expected.

To try this, change the name of your test_add method to add_test like this:

class TestCalculator(unittest.TestCase): def add_test(self): self.assertEqual(calculator.add(1, 2), 3) self.assertEqual(calculator.add(-1, 1), 0) self.assertEqual(calculator.add(-1, -1), -2) self.assertEqual(calculator.add(0, 0), 0)

Now, if you run the command python test_calculator.py, you will get a message similar to this:

----------------------------------------------------------------------Ran 0 tests in 0.000sOK

Notice that the preceding output shows that zero tests ran. Now, change your method's name back to test_add. Also, change the operator in the add function of your calculator.py back to addition (+). Now, rerun the test with the command python test_calculator.py and compare your output to the preceding output.

It's a common practice for developers to handle invalid input by raising exceptions. So, it's important to write tests that check for these exceptions.

For example, Python will raise a ZeroDivisionError if you try to divide any number by zero. You can use the unittest module to test for such errors.

Now, modify your test_calculator.py file to include a test method for your divide function:

import unittestimport calculatorclass TestMathOperations(unittest.TestCase): def test_add(self): self.assertEqual(calculator.add(1, 2), 3) self.assertEqual(calculator.add(-1, 1), 0) self.assertEqual(calculator.add(-1, -1), -2) self.assertEqual(calculator.add(0, 0), 0) def test_divide(self): self.assertEqual(calculator.divide(10, 2), 5) self.assertEqual(calculator.divide(9, 3), 3) self.assertEqual(calculator.divide(-6, 2), -3) self.assertEqual(calculator.divide(0, 1), 0) with self.assertRaises(ZeroDivisionError): calculator.divide(10, 0)if __name__ == "__main__": unittest.main()

In the preceding code, your new test_divide method tests representative values just like your test_add method. But there is new code at the end that uses assertRaises. assertRaises is another assert method provided by unittest to check if your code raises an exception. Here, you used the method to check for ZeroDivisionError.

So, if you run the tests now, you will get a message showing two dots (..) and indicating that you ran two successful tests:

..----------------------------------------------------------------------Ran 2 tests in 0.000sOK

Conclusion

This article has taught you the basics of unit testing in Python using the unittest testing framework.

You've learned the importance of independently testing individual units of your application and the reasons unittest is still a popular choice among Python developers. Also, you've learned how to write basic test cases for the add and divide functions in your simple calculator program.

With this knowledge, you can now confidently create tests that ensure your code behaves as expected, making it more robust and maintainable. I encourage you to apply these lessons by writing tests for the remaining subtract and multiply functions in your calculator program.

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

ADVERTIsem*nT

How to Write Unit Tests in Python – with Example Test Code (3)
Damilola Oladele

Damilola Oladele is a software developer and technical writer. He is passionate about community and learning new technologies.

If you read this far, thank the author to show them you care.

Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. Get started

ADVERTIsem*nT

How to Write Unit Tests in Python – with Example Test Code (2024)

References

Top Articles
7 Horrorfilme von Wes Craven, die ihr gesehen haben solltet - 100 Years of Terror
Wes Cravens "Verflucht": Der sich den Wolf dreht
Automated refuse, recycling for most residences; schedule announced | Lehigh Valley Press
Bleak Faith: Forsaken – im Test (PS5)
Tabc On The Fly Final Exam Answers
Chelsea player who left on a free is now worth more than Palmer & Caicedo
Crossed Eyes (Strabismus): Symptoms, Causes, and Diagnosis
How Much Is 10000 Nickels
BULLETIN OF ANIMAL HEALTH AND PRODUCTION IN AFRICA
Aiken County government, school officials promote penny tax in North Augusta
Beds From Rent-A-Center
What's New on Hulu in October 2023
Irving Hac
South Bend Tribune Online
C-Date im Test 2023 – Kosten, Erfahrungen & Funktionsweise
Oc Craiglsit
Funny Marco Birth Chart
Cinebarre Drink Menu
What is Rumba and How to Dance the Rumba Basic — Duet Dance Studio Chicago | Ballroom Dance in Chicago
使用 RHEL 8 时的注意事项 | Red Hat Product Documentation
Why Is 365 Market Troy Mi On My Bank Statement
Aps Day Spa Evesham
Is A Daytona Faster Than A Scat Pack
Holiday Gift Bearer In Egypt
Mini Handy 2024: Die besten Mini Smartphones | Purdroid.de
Utexas Iot Wifi
27 Modern Dining Room Ideas You'll Want to Try ASAP
Motorcycle Blue Book Value Honda
Wheeling Matinee Results
Senior Houses For Sale Near Me
Greater Keene Men's Softball
Maxpreps Field Hockey
Myfxbook Historical Data
Kazwire
Google Chrome-webbrowser
Indio Mall Eye Doctor
Best Restaurants Minocqua
11526 Lake Ave Cleveland Oh 44102
Firestone Batteries Prices
The best specialist spirits store | Spirituosengalerie Stuttgart
Chathuram Movie Download
Kb Home The Overlook At Medio Creek
Academic Calendar / Academics / Home
Spreading Unverified Info Crossword Clue
Ephesians 4 Niv
Minterns German Shepherds
Mytmoclaim Tracking
Compete My Workforce
Ret Paladin Phase 2 Bis Wotlk
Lsreg Att
Naughty Natt Farting
Bunbrat
Latest Posts
Article information

Author: Virgilio Hermann JD

Last Updated:

Views: 6001

Rating: 4 / 5 (41 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Virgilio Hermann JD

Birthday: 1997-12-21

Address: 6946 Schoen Cove, Sipesshire, MO 55944

Phone: +3763365785260

Job: Accounting Engineer

Hobby: Web surfing, Rafting, Dowsing, Stand-up comedy, Ghost hunting, Swimming, Amateur radio

Introduction: My name is Virgilio Hermann JD, I am a fine, gifted, beautiful, encouraging, kind, talented, zealous person who loves writing and wants to share my knowledge and understanding with you.