Software Testing Unit Testing#
Unit Testing#
Definition: Unit testing involves testing individual components or units of code in isolation. These units could be functions, methods, or classes.
Purpose: To verify that each unit works as expected and meets its specific requirements.
Benefits:
Early detection of defects
Improved code quality
Increased code maintainability
Supports regression testing
Integration Testing#
Definition: Integration testing combines multiple units or components to test their interactions and communication.
Purpose: To verify that different parts of the software work together as expected.
Benefits:
Identifies interface-related defects
Ensures data integrity and flow
Improves system stability
UnitTest#
Unittest is Python’s standard library for writing and running unit tests. It provides a structured approach to testing individual units of code (functions, methods, classes) to ensure they behave as expected.
https://docs.python.org/3/library/unittest.html
Key Features:#
Test Cases: Define individual test scenarios using the
TestCase
class.Test Suites: Organize test cases into collections for efficient execution.
Assertions: Verify expected outcomes using methods like
assertEqual
,assertTrue
, etc.Fixtures: Set up and tear down test environments using
setUp()
andtearDown()
methods.
UnitTest Examples#
Basic Example: Testing a Simple Function#
Python
"""
Unit Testing is for the testing of functions
and methods
"""
import unittest
def add(x, y):
return x + y
class TestAdd(unittest.TestCase):
def test_add_positive_true(self):
result = add(2, 3)
self.assertEqual(result, 5)
def test_add_positive_true_bad(self):
result = add(2, 3)
self.assertEqual(result, 100)
def test_add_negative(self):
result = add(-1, 2)
self.assertEqual(result, 1)
# ------ Examples of comparitive values
def test_3_gt_2(self):
self.assertGreater(3,2);
def test_2_gt_3(self):
self.assertGreater(2,3);
if __name__ == '__main__':
# Setting the verbosity to 2
# Gives details on what tests
# were ran and the outcomes
unittest.main(verbosity=2)
"""
output:
test_2_gt_3 (__main__.TestAdd.test_2_gt_3) ... FAIL
test_3_gt_2 (__main__.TestAdd.test_3_gt_2) ... ok
test_add_negative (__main__.TestAdd.test_add_negative) ... ok
test_add_positive_true (__main__.TestAdd.test_add_positive_true) ... ok
test_add_positive_true_bad (__main__.TestAdd.test_add_positive_true_bad) ... FAIL
======================================================================
FAIL: test_2_gt_3 (__main__.TestAdd.test_2_gt_3)
----------------------------------------------------------------------
Traceback (most recent call last):
File "e:\My Drive\0_CSCI_127_JBD\Teaching_Modules\Module_Testing\unitTesting_example1.py", line 30, in test_2_gt_3
self.assertGreater(2,3);
^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 2 not greater than 3
======================================================================
FAIL: test_add_positive_true_bad (__main__.TestAdd.test_add_positive_true_bad)
----------------------------------------------------------------------
Traceback (most recent call last):
File "e:\My Drive\0_CSCI_127_JBD\Teaching_Modules\Module_Testing\unitTesting_example1.py", line 20, in test_add_positive_true_bad
self.assertEqual(result, 100)
AssertionError: 5 != 100
----------------------------------------------------------------------
Ran 5 tests in 0.004s
FAILED (failures=2)
"""
Testing a Class Method#
Python
"""
Unit Testing is for the testing of functions
and methods
"""
import unittest
class AddCaclulator:
def __init__(self) -> None:
pass
def add(x, y):
return x + y
class TestAdd(unittest.TestCase):
def test_add_positive_true(self):
result = myCalculator.add(2, 3)
self.assertEqual(result, 5)
def test_add_positive_true_bad(self):
result = myCalculator.add(2, 3)
self.assertEqual(result, 100)
def test_add_negative(self):
result = myCalculator.add(-1, 2)
self.assertEqual(result, 1)
# ------ Examples of comparitive values
def test_3_gt_2(self):
self.assertGreater(3,2);
def test_2_gt_3(self):
self.assertGreater(2,3);
# global object
myCalculator = AddCaclulator
if __name__ == '__main__':
# Setting the verbosity to 2
# Gives details on what tests
# were ran and the outcomes
unittest.main(verbosity=2)
'''
Output
# -------------------
test_2_gt_3 (__main__.TestAdd.test_2_gt_3) ... FAIL
test_3_gt_2 (__main__.TestAdd.test_3_gt_2) ... ok
test_add_negative (__main__.TestAdd.test_add_negative) ... ok
test_add_positive_true (__main__.TestAdd.test_add_positive_true)
... ok
test_add_positive_true_bad (__main__.TestAdd.test_add_positive_true_bad) ... FAIL
======================================================================
FAIL: test_2_gt_3 (__main__.TestAdd.test_2_gt_3)
----------------------------------------------------------------------
Traceback (most recent call last):
File "e:\My Drive\0_CSCI_127_JBD\Teaching_Modules\Module_Testing\unitTesting_example2.py", line 36, in test_2_gt_3
self.assertGreater(2,3);
^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 2 not greater than 3
======================================================================
FAIL: test_add_positive_true_bad (__main__.TestAdd.test_add_positive_true_bad)
----------------------------------------------------------------------
Traceback (most recent call last):
File "e:\My Drive\0_CSCI_127_JBD\Teaching_Modules\Module_Testing\unitTesting_example2.py", line 25, in test_add_positive_true_bad
self.assertEqual(result, 100)
AssertionError: 5 != 100
----------------------------------------------------------------------
Ran 5 tests in 0.004s
FAILED (failures=2)
'''
Using Assertions#
Unittest provides several assertion methods to check different conditions:
Method |
Checks that |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
There are also other methods used to perform more specific checks, such as: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a and b have the same elements in the same number, regardless of their order. |
Test Fixtures#
Unittest provides setUp()
and tearDown()
methods to set up and clean up resources before and after each test case:
Python
import unittest
class TestDatabase(unittest.TestCase):
def setUp(self):
# Connect to database
def tearDown(self):
# Close database connection
def test_query(self):
# Perform database query
if __name__ == '__main__':
unittest.main()
Running Tests#
To run the tests, you can use the following command in your terminal:
Cmd
python test_file.py
For more detailed output, use the -v
flag:
Cmd
python -m unittest -v test_file.py
Remember:
Each test case should be independent.
Test cases should cover different scenarios and edge cases.
Use clear and descriptive test case names.
Strive for high test coverage.