unittest: Add subtest usage examples.

This work was funded by Planet Innovation.
pull/505/merge
Gavin Douch 2023-02-16 11:40:58 +11:00 zatwierdzone przez Damien George
rodzic e3371bef6c
commit 23018a86bf
1 zmienionych plików z 214 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,214 @@
"""Tests using unittest.subtest as an example reference for how it is used"""
import unittest
def factorial(value: int) -> int:
"""Iterative factorial algorithm implementation"""
result = 1
for i in range(1, value + 1):
result *= i
return result
class Person:
"""Represents a person with a name, age, and who can make friends"""
def __init__(self, name: str, age: int) -> None:
self.name = name
self.age = age
self.friends = set()
def __repr__(self) -> str:
return f"Person({self.name})"
def add_friend(self, friend):
"""Logs that this Person has made a new friend"""
self.friends.add(friend)
def has_friend(self, friend_candidate) -> bool:
"""Determines if this Person has the friend `friend_candidate`"""
return friend_candidate in self.friends
def is_oldest_friend(self) -> bool:
"""Determines whether this Person is the oldest out of themself and their friends"""
return self.age > max(friend.age for friend in self.friends)
class TestSubtest(unittest.TestCase):
"""Examples/tests of unittest.subTest()"""
def test_sorted(self) -> None:
"""Test that the selection sort function correctly sorts lists"""
tests = [
{
"unsorted": [-68, 15, 52, -54, -64, 20, 2, 66, 33],
"sorted": [-68, -64, -54, 2, 15, 20, 33, 52, 66],
"correct": True,
},
{
"unsorted": [-68, 15, 52, -54, -64, 20, 2, 66, 33],
"sorted": [-68, -54, -64, 2, 15, 20, 33, 52, 66],
"correct": False,
},
{
"unsorted": [-68, 15, 52, 54, -64, 20, 2, 66, 33],
"sorted": [-68, -64, -54, 2, 15, 20, 33, 52, 66],
"correct": False,
},
{
"unsorted": [],
"sorted": [],
"correct": True,
},
{
"unsorted": [42],
"sorted": [42],
"correct": True,
},
{
"unsorted": [42],
"sorted": [],
"correct": False,
},
{
"unsorted": [],
"sorted": [24],
"correct": False,
},
{
"unsorted": [43, 44],
"sorted": [43, 44],
"correct": True,
},
{
"unsorted": [44, 43],
"sorted": [43, 44],
"correct": True,
},
]
for test in tests:
with self.subTest(): # Subtests continue to be tested, even if an earlier one fails
if test["correct"]: # Tests that match what is expected
self.assertEqual(sorted(test["unsorted"]), test["sorted"])
else: # Tests that are meant to fail
with self.assertRaises(AssertionError):
self.assertEqual(sorted(test["unsorted"]), test["sorted"])
def test_factorial(self) -> None:
"""Test that the factorial fuction correctly calculates factorials
Makes use of `msg` argument in subtest method to clarify which subtests had an
error in the results
"""
tests = [
{
"operand": 0,
"result": 1,
"correct": True,
},
{
"operand": 1,
"result": 1,
"correct": True,
},
{
"operand": 1,
"result": 0,
"correct": False,
},
{
"operand": 2,
"result": 2,
"correct": True,
},
{
"operand": 3,
"result": 6,
"correct": True,
},
{
"operand": 3,
"result": -6,
"correct": False,
},
{
"operand": 4,
"result": 24,
"correct": True,
},
{
"operand": 15,
"result": 1_307_674_368_000,
"correct": True,
},
{
"operand": 15,
"result": 1_307_674_368_001,
"correct": False,
},
{
"operand": 11,
"result": 39_916_800,
"correct": True,
},
]
for test in tests:
with self.subTest(
f"{test['operand']}!"
): # Let's us know we were testing "x!" when we get an error
if test["correct"]:
self.assertEqual(factorial(test["operand"]), test["result"])
else:
with self.assertRaises(AssertionError):
self.assertEqual(factorial(test["operand"]), test["result"])
def test_person(self) -> None:
"""Test the Person class and its friend-making ability
Makes use of subtest's params to specify relevant data about the tests, which is
helpful for debugging
"""
# Create a friendship
alice = Person("Alice", 22)
bob = Person("Bob", 23)
alice.add_friend(bob)
# Test friendship init
with self.subTest(
"Alice should have Bob as a friend", name=alice.name, friends=bob.friends
): # Params `name` and `friends` provide useful data for debugging purposes
self.assertTrue(alice.has_friend(bob))
with self.subTest(
"Bob should not have Alice as a friend", name=bob.name, friends=bob.friends
):
self.assertFalse(bob.has_friend(alice))
# Friendship is not always commutative, so Bob is not implicitly friends with Alice
with self.subTest("Alice and Bob should not both be friends with eachother"):
with self.assertRaises(AssertionError):
self.assertTrue(bob.has_friend(alice) and alice.has_friend(bob))
# Bob becomes friends with Alice
bob.add_friend(alice)
with self.subTest(
"Bob should now have Alice as a friend", name=bob.name, friends=bob.friends
):
self.assertTrue(bob.has_friend(alice))
with self.subTest(
"Bob should be the oldest of his friends",
age=bob.age,
friend_ages=[friend.age for friend in bob.friends],
): # Different params can be used for different subtests in the same test
self.assertTrue(bob.is_oldest_friend())
if __name__ == "__main__":
unittest.main()