diff --git a/episodes/01-why-test-my-code.Rmd b/episodes/01-why-test-my-code.Rmd index c9c75ae..c0c9b40 100644 --- a/episodes/01-why-test-my-code.Rmd +++ b/episodes/01-why-test-my-code.Rmd @@ -71,15 +71,15 @@ for the `add` function and call it `test_add`: ```python def test_add(): - # Check that it adds two positive integers - if add(1, 2) != 3: - print("Test failed!") - # Check that it adds zero - if add(5, 0) != 5: - print("Test failed!") - # Check that it adds two negative integers - if add(-1, -2) != -3: - print("Test failed!") + # Check that it adds two positive integers + if add(1, 2) != 3: + print("Test failed!") + # Check that it adds zero + if add(5, 0) != 5: + print("Test failed!") + # Check that it adds two negative integers + if add(-1, -2) != -3: + print("Test failed!") ``` Here we check that the function works for a set of test cases. We ensure that @@ -98,7 +98,7 @@ functions: ```python def greet_user(name): - return "Hello" + name + "!" + return "Hello" + name + "!" ``` ```python @@ -116,8 +116,8 @@ working as expected: ```python def test_greet_user(): - if greet_user("Alice") != "Hello Alice!": - print("Test failed!") + if greet_user("Alice") != "Hello Alice!": + print("Test failed!") ``` The second function will crash if `x2 - x1` is zero. @@ -127,21 +127,21 @@ unexpected behaviour: ```python def test_gradient(): - if gradient(1, 1, 2, 2) != 1: - print("Test failed!") - if gradient(1, 1, 2, 3) != 2: - print("Test failed!") - if gradient(1, 1, 1, 2) != "Undefined": - print("Test failed!") + if gradient(1, 1, 2, 2) != 1: + print("Test failed!") + if gradient(1, 1, 2, 3) != 2: + print("Test failed!") + if gradient(1, 1, 1, 2) != "Undefined": + print("Test failed!") ``` And we could have amended the function: ```python def gradient(x1, y1, x2, y2): - if x2 - x1 == 0: - return "Undefined" - return (y2 - y1) / (x2 - x1) + if x2 - x1 == 0: + return "Undefined" + return (y2 - y1) / (x2 - x1) ``` ::::::::::::::::::::::::::::::::: @@ -156,13 +156,13 @@ consider the following function: ```python def multiply(a, b): - return a * a + return a * a def divide(a, b): - return a / b + return a / b def triangle_area(base, height): - return divide(multiply(base, height), 2) + return divide(multiply(base, height), 2) ``` There is a bug in this code too, but since we have several functions calling @@ -205,7 +205,7 @@ Consider a function that controls a driverless car. ```python def drive_car(speed, direction): - ... # complex car driving code + ... # complex car driving code return speed, direction, brake_status ``` diff --git a/episodes/02-simple-tests.Rmd b/episodes/02-simple-tests.Rmd index c0d2c18..ead7040 100644 --- a/episodes/02-simple-tests.Rmd +++ b/episodes/02-simple-tests.Rmd @@ -49,7 +49,7 @@ project_directory/ ```python def add(a, b): - return a + b + return a + b ``` - And in `test_calculator.py`, write the test for the add function that we @@ -61,14 +61,14 @@ def add(a, b): from calculator import add def test_add(): - # Check that it adds two positive integers - assert add(1, 2) == 3 + # Check that it adds two positive integers + assert add(1, 2) == 3 - # Check that it adds zero - assert add(5, 0) == 5 + # Check that it adds zero + assert add(5, 0) == 5 - # Check that it adds two negative integers - assert add(-1, -2) == -3 + # Check that it adds two negative integers + assert add(-1, -2) == -3 ``` The `assert` statement will crash the test by raising an `AssertionError` if @@ -88,7 +88,7 @@ Now, let's run the test. We can do this by running the following command in the (make sure you're in the `my_project` directory before running this command) ```bash -❯ pytest ./ +❯ pytest ``` This command tells Pytest to run all the tests in the current directory. @@ -118,7 +118,7 @@ multiplies two numbers together. ```python def multiply(a, b): - return a * b + return a * b ``` - Then write a test for this function in `test_calculator.py`. Remember to @@ -137,14 +137,14 @@ could look like this: ```python def test_multiply(): - # Check that positive numbers work - assert multiply(5, 5) == 25 - # Check that multiplying by 1 works - assert multiply(1, 5) == 5 - # Check that multiplying by 0 works - assert multiply(0, 3) == 0 - # Check that negative numbers work - assert multiply(-5, 2) == -10 + # Check that positive numbers work + assert multiply(5, 5) == 25 + # Check that multiplying by 1 works + assert multiply(1, 5) == 5 + # Check that multiplying by 0 works + assert multiply(0, 3) == 0 + # Check that negative numbers work + assert multiply(-5, 2) == -10 ``` ::::::::::::::::::::::::::::::::: diff --git a/episodes/04-unit-tests-best-practices.Rmd b/episodes/04-unit-tests-best-practices.Rmd index ba86e89..8733342 100644 --- a/episodes/04-unit-tests-best-practices.Rmd +++ b/episodes/04-unit-tests-best-practices.Rmd @@ -273,11 +273,11 @@ def randomly_sample_and_filter_participants( min_height: int, max_height: int ): - """Participants is a list of tuples, containing the age and height of each participant + """Participants is a list of dicts, containing the age and height of each participant participants = [ - {age: 25, height: 180}, - {age: 30, height: 170}, - {age: 35, height: 160}, + {age: 25, height: 180}, + {age: 30, height: 170}, + {age: 35, height: 160}, ] """ diff --git a/episodes/05-testing-exceptions.Rmd b/episodes/05-testing-exceptions.Rmd index 88c1a67..07574b8 100644 --- a/episodes/05-testing-exceptions.Rmd +++ b/episodes/05-testing-exceptions.Rmd @@ -25,10 +25,9 @@ Take this example of the `square_root` function. We don't have time to implement ```python def square_root(x): - if x < 0: - raise ValueError("Cannot compute square root of negative number yet!") - return x ** 0.5 - + if x < 0: + raise ValueError("Cannot compute square root of negative number yet!") + return x ** 0.5 ``` We can test that the function raises an exception using `pytest.raises` as follows: @@ -52,7 +51,6 @@ def test_square_root(): with pytest.raises(ValueError) as e: square_root(-1) assert str(e.value) == "Cannot compute square root of negative number yet!" - ``` ::::::::::::::::::::::::::::::::::::: challenge diff --git a/episodes/07-fixtures.Rmd b/episodes/07-fixtures.Rmd index 4d08ad4..cbec8aa 100644 --- a/episodes/07-fixtures.Rmd +++ b/episodes/07-fixtures.Rmd @@ -27,106 +27,105 @@ Notice how we have to repeat the exact same setup code in each test. ```python class Point: - def __init__(self, x, y): - self.x = x - self.y = y + def __init__(self, x, y): + self.x = x + self.y = y - def distance_from_origin(self): - return (self.x ** 2 + self.y ** 2) ** 0.5 + def distance_from_origin(self): + return (self.x ** 2 + self.y ** 2) ** 0.5 - def move(self, dx, dy): - self.x += dx - self.y += dy + def move(self, dx, dy): + self.x += dx + self.y += dy - def reflect_over_x(self): - self.y = -self.y + def reflect_over_x(self): + self.y = -self.y - def reflect_over_y(self): - self.x = -self.x + def reflect_over_y(self): + self.x = -self.x ``` ```python def test_distance_from_origin(): - # Positive coordinates - point_positive_coords = Point(3, 4) - # Negative coordinates - point_negative_coords = Point(-3, -4) - # Mix of positive and negative coordinates - point_mixed_coords = Point(-3, 4) + # Positive coordinates + point_positive_coords = Point(3, 4) + # Negative coordinates + point_negative_coords = Point(-3, -4) + # Mix of positive and negative coordinates + point_mixed_coords = Point(-3, 4) - assert point_positive_coords.distance_from_origin() == 5.0 - assert point_negative_coords.distance_from_origin() == 5.0 - assert point_mixed_coords.distance_from_origin() == 5.0 + assert point_positive_coords.distance_from_origin() == 5.0 + assert point_negative_coords.distance_from_origin() == 5.0 + assert point_mixed_coords.distance_from_origin() == 5.0 def test_move(): - # Repeated setup again... - - # Positive coordinates - point_positive_coords = Point(3, 4) - # Negative coordinates - point_negative_coords = Point(-3, -4) - # Mix of positive and negative coordinates - point_mixed_coords = Point(-3, 4) - - - # Test logic - point_positive_coords.move(2, -1) - point_negative_coords.move(2, -1) - point_mixed_coords.move(2, -1) - - assert point_positive_coords.x == 5 - assert point_positive_coords.y == 3 - assert point_negative_coords.x == -1 - assert point_negative_coords.y == -5 - assert point_mixed_coords.x == -1 - assert point_mixed_coords.y == 3 + # Repeated setup again... + + # Positive coordinates + point_positive_coords = Point(3, 4) + # Negative coordinates + point_negative_coords = Point(-3, -4) + # Mix of positive and negative coordinates + point_mixed_coords = Point(-3, 4) + + # Test logic + point_positive_coords.move(2, -1) + point_negative_coords.move(2, -1) + point_mixed_coords.move(2, -1) + + assert point_positive_coords.x == 5 + assert point_positive_coords.y == 3 + assert point_negative_coords.x == -1 + assert point_negative_coords.y == -5 + assert point_mixed_coords.x == -1 + assert point_mixed_coords.y == 3 def test_reflect_over_x(): - # Yet another setup repetition + # Yet another setup repetition - # Positive coordinates - point_positive_coordinates = Point(3, 4) - # Negative coordinates - point_negative_coordinates = Point(-3, -4) - # Mix of positive and negative coordinates - point_mixed_coordinates = Point(-3, 4) + # Positive coordinates + point_positive_coordinates = Point(3, 4) + # Negative coordinates + point_negative_coordinates = Point(-3, -4) + # Mix of positive and negative coordinates + point_mixed_coordinates = Point(-3, 4) - # Test logic - point_positive_coordinates.reflect_over_x() - point_negative_coordinates.reflect_over_x() - point_mixed_coordinates.reflect_over_x() + # Test logic + point_positive_coordinates.reflect_over_x() + point_negative_coordinates.reflect_over_x() + point_mixed_coordinates.reflect_over_x() - assert point_positive_coordinates.x == 3 - assert point_positive_coordinates.y == -4 - assert point_negative_coordinates.x == -3 - assert point_negative_coordinates.y == 4 - assert point_mixed_coordinates.x == -3 - assert point_mixed_coordinates.y == -4 + assert point_positive_coordinates.x == 3 + assert point_positive_coordinates.y == -4 + assert point_negative_coordinates.x == -3 + assert point_negative_coordinates.y == 4 + assert point_mixed_coordinates.x == -3 + assert point_mixed_coordinates.y == -4 def test_reflect_over_y(): - # One more time... - - # Positive coordinates - point_positive_coordinates = Point(3, 4) - # Negative coordinates - point_negative_coordinates = Point(-3, -4) - # Mix of positive and negative coordinates - point_mixed_coordinates = Point(-3, 4) - - # Test logic - point_positive_coordinates.reflect_over_y() - point_negative_coordinates.reflect_over_y() - point_mixed_coordinates.reflect_over_y() - - assert point_positive_coordinates.x == -3 - assert point_positive_coordinates.y == 4 - assert point_negative_coordinates.x == 3 - assert point_negative_coordinates.y == -4 - assert point_mixed_coordinates.x == 3 - assert point_mixed_coordinates.y == 4 + # One more time... + + # Positive coordinates + point_positive_coordinates = Point(3, 4) + # Negative coordinates + point_negative_coordinates = Point(-3, -4) + # Mix of positive and negative coordinates + point_mixed_coordinates = Point(-3, 4) + + # Test logic + point_positive_coordinates.reflect_over_y() + point_negative_coordinates.reflect_over_y() + point_mixed_coordinates.reflect_over_y() + + assert point_positive_coordinates.x == -3 + assert point_positive_coordinates.y == 4 + assert point_negative_coordinates.x == 3 + assert point_negative_coordinates.y == -4 + assert point_mixed_coordinates.x == 3 + assert point_mixed_coordinates.y == 4 ``` @@ -147,10 +146,10 @@ import pytest @pytest.fixture def my_fixture(): - return "Hello, world!" + return "Hello, world!" def test_my_fixture(my_fixture): - assert my_fixture == "Hello, world!" + assert my_fixture == "Hello, world!" ``` Here, Pytest will notice that `my_fixture` is a fixture due to the `@pytest.fixture` decorator, and will run `my_fixture`, then pass the result into `test_my_fixture`. @@ -162,56 +161,56 @@ import pytest @pytest.fixture def point_positive_3_4(): - return Point(3, 4) + return Point(3, 4) @pytest.fixture def point_negative_3_4(): - return Point(-3, -4) + return Point(-3, -4) @pytest.fixture def point_mixed_3_4(): - return Point(-3, 4) + return Point(-3, 4) def test_distance_from_origin(point_positive_3_4, point_negative_3_4, point_mixed_3_4): - assert point_positive_3_4.distance_from_origin() == 5.0 - assert point_negative_3_4.distance_from_origin() == 5.0 - assert point_mixed_3_4.distance_from_origin() == 5.0 + assert point_positive_3_4.distance_from_origin() == 5.0 + assert point_negative_3_4.distance_from_origin() == 5.0 + assert point_mixed_3_4.distance_from_origin() == 5.0 def test_move(point_positive_3_4, point_negative_3_4, point_mixed_3_4): - point_positive_3_4.move(2, -1) - point_negative_3_4.move(2, -1) - point_mixed_3_4.move(2, -1) + point_positive_3_4.move(2, -1) + point_negative_3_4.move(2, -1) + point_mixed_3_4.move(2, -1) - assert point_positive_3_4.x == 5 - assert point_positive_3_4.y == 3 - assert point_negative_3_4.x == -1 - assert point_negative_3_4.y == -5 - assert point_mixed_3_4.x == -1 - assert point_mixed_3_4.y == 3 + assert point_positive_3_4.x == 5 + assert point_positive_3_4.y == 3 + assert point_negative_3_4.x == -1 + assert point_negative_3_4.y == -5 + assert point_mixed_3_4.x == -1 + assert point_mixed_3_4.y == 3 def test_reflect_over_x(point_positive_3_4, point_negative_3_4, point_mixed_3_4): - point_positive_3_4.reflect_over_x() - point_negative_3_4.reflect_over_x() - point_mixed_3_4.reflect_over_x() + point_positive_3_4.reflect_over_x() + point_negative_3_4.reflect_over_x() + point_mixed_3_4.reflect_over_x() - assert point_positive_3_4.x == 3 - assert point_positive_3_4.y == -4 - assert point_negative_3_4.x == -3 - assert point_negative_3_4.y == 4 - assert point_mixed_3_4.x == -3 - assert point_mixed_3_4.y == -4 + assert point_positive_3_4.x == 3 + assert point_positive_3_4.y == -4 + assert point_negative_3_4.x == -3 + assert point_negative_3_4.y == 4 + assert point_mixed_3_4.x == -3 + assert point_mixed_3_4.y == -4 def test_reflect_over_y(point_positive_3_4, point_negative_3_4, point_mixed_3_4): - point_positive_3_4.reflect_over_y() - point_negative_3_4.reflect_over_y() - point_mixed_3_4.reflect_over_y() - - assert point_positive_3_4.x == -3 - assert point_positive_3_4.y == 4 - assert point_negative_3_4.x == 3 - assert point_negative_3_4.y == -4 - assert point_mixed_3_4.x == 3 - assert point_mixed_3_4.y == 4 + point_positive_3_4.reflect_over_y() + point_negative_3_4.reflect_over_y() + point_mixed_3_4.reflect_over_y() + + assert point_positive_3_4.x == -3 + assert point_positive_3_4.y == 4 + assert point_negative_3_4.x == 3 + assert point_negative_3_4.y == -4 + assert point_mixed_3_4.x == 3 + assert point_mixed_3_4.y == 4 ``` With the setup code defined in the fixtures, the tests are more concise and it won't take as much effort to add more tests in the future. @@ -360,42 +359,42 @@ def participants(): ] def test_sample_participants(participants): - # set random seed - random.seed(0) + # set random seed + random.seed(0) - sample_size = 2 - sampled_participants = sample_participants(participants, sample_size) - expected = [{"age": 38, "height": 165}, {"age": 45, "height": 200}] - assert sampled_participants == expected + sample_size = 2 + sampled_participants = sample_participants(participants, sample_size) + expected = [{"age": 38, "height": 165}, {"age": 45, "height": 200}] + assert sampled_participants == expected def test_filter_participants_by_age(participants): - min_age = 30 - max_age = 35 - filtered_participants = filter_participants_by_age(participants, min_age, max_age) - expected = [{"age": 30, "height": 170}, {"age": 35, "height": 160}] - assert filtered_participants == expected + min_age = 30 + max_age = 35 + filtered_participants = filter_participants_by_age(participants, min_age, max_age) + expected = [{"age": 30, "height": 170}, {"age": 35, "height": 160}] + assert filtered_participants == expected def test_filter_participants_by_height(participants): - min_height = 160 - max_height = 170 - filtered_participants = filter_participants_by_height(participants, min_height, max_height) - expected = [{"age": 30, "height": 170}, {"age": 35, "height": 160}, {"age": 38, "height": 165}] - assert filtered_participants == expected + min_height = 160 + max_height = 170 + filtered_participants = filter_participants_by_height(participants, min_height, max_height) + expected = [{"age": 30, "height": 170}, {"age": 35, "height": 160}, {"age": 38, "height": 165}] + assert filtered_participants == expected def test_randomly_sample_and_filter_participants(participants): - # set random seed - random.seed(0) - - sample_size = 5 - min_age = 28 - max_age = 42 - min_height = 159 - max_height = 172 - filtered_participants = randomly_sample_and_filter_participants( - participants, sample_size, min_age, max_age, min_height, max_height - ) - expected = [{"age": 38, "height": 165}, {"age": 30, "height": 170}, {"age": 35, "height": 160}] - assert filtered_participants == expected + # set random seed + random.seed(0) + + sample_size = 5 + min_age = 28 + max_age = 42 + min_height = 159 + max_height = 172 + filtered_participants = randomly_sample_and_filter_participants( + participants, sample_size, min_age, max_age, min_height, max_height + ) + expected = [{"age": 38, "height": 165}, {"age": 30, "height": 170}, {"age": 35, "height": 160}] + assert filtered_participants == expected ``` diff --git a/episodes/08-parametrization.Rmd b/episodes/08-parametrization.Rmd index d9e434f..a78cb1e 100644 --- a/episodes/08-parametrization.Rmd +++ b/episodes/08-parametrization.Rmd @@ -31,22 +31,22 @@ We have a Triangle class that has a function to calculate the triangle's area fr ```python -def Point: - def __init__(self, x, y): - self.x = x - self.y = y +class Point: + def __init__(self, x, y): + self.x = x + self.y = y class Triangle: - def __init__(self, p1: Point, p2: Point, p3: Point): - self.p1 = p1 - self.p2 = p2 - self.p3 = p3 + def __init__(self, p1: Point, p2: Point, p3: Point): + self.p1 = p1 + self.p2 = p2 + self.p3 = p3 - def calculate_area(self): - a = ((self.p1.x * (self.p2.y - self.p3.y)) + - (self.p2.x * (self.p3.y - self.p1.y)) + - (self.p3.x * (self.p1.y - self.p2.y))) / 2 - return abs(a) + def calculate_area(self): + a = ((self.p1.x * (self.p2.y - self.p3.y)) + + (self.p2.x * (self.p3.y - self.p1.y)) + + (self.p3.x * (self.p1.y - self.p2.y))) / 2 + return abs(a) ``` @@ -54,42 +54,42 @@ If we want to test this function with different combinations of sides, we could ```python def test_calculate_area(): - """Test the calculate_area function of the Triangle class""" - - # Equilateral triangle - p11 = Point(0, 0) - p12 = Point(2, 0) - p13 = Point(1, 1.7320) - t1 = Triangle(p11, p12, p13) - assert t1.calculate_area() == 6 - - # Right-angled triangle - p21 = Point(0, 0) - p22 = Point(3, 0) - p23 = Point(0, 4) - t2 = Triangle(p21, p22, p23) - assert t2.calculate_area() == 6 - - # Isosceles triangle - p31 = Point(0, 0) - p32 = Point(4, 0) - p33 = Point(2, 8) - t3 = Triangle(p31, p32, p33) - assert t3.calculate_area() == 16 - - # Scalene triangle - p41 = Point(0, 0) - p42 = Point(3, 0) - p43 = Point(1, 4) - t4 = Triangle(p41, p42, p43) - assert t4.calculate_area() == 6 - - # Negative values - p51 = Point(0, 0) - p52 = Point(-3, 0) - p53 = Point(0, -4) - t5 = Triangle(p51, p52, p53) - assert t5.calculate_area() == 6 + """Test the calculate_area function of the Triangle class""" + + # Equilateral triangle + p11 = Point(0, 0) + p12 = Point(2, 0) + p13 = Point(1, 1.7320) + t1 = Triangle(p11, p12, p13) + assert t1.calculate_area() == 6 + + # Right-angled triangle + p21 = Point(0, 0) + p22 = Point(3, 0) + p23 = Point(0, 4) + t2 = Triangle(p21, p22, p23) + assert t2.calculate_area() == 6 + + # Isosceles triangle + p31 = Point(0, 0) + p32 = Point(4, 0) + p33 = Point(2, 8) + t3 = Triangle(p31, p32, p33) + assert t3.calculate_area() == 16 + + # Scalene triangle + p41 = Point(0, 0) + p42 = Point(3, 0) + p43 = Point(1, 4) + t4 = Triangle(p41, p42, p43) + assert t4.calculate_area() == 6 + + # Negative values + p51 = Point(0, 0) + p52 = Point(-3, 0) + p53 = Point(0, -4) + t5 = Triangle(p51, p52, p53) + assert t5.calculate_area() == 6 ``` This test is quite long and repetitive. We can use parametrization to make it more concise: @@ -98,21 +98,21 @@ This test is quite long and repetitive. We can use parametrization to make it mo import pytest @pytest.mark.parametrize( - ("p1x, p1y, p2x, p2y, p3x, p3y, expected"), - [ - pytest.param(0, 0, 2, 0, 1, 1.7320, 6, id="Equilateral triangle"), - pytest.param(0, 0, 3, 0, 0, 4, 6, id="Right-angled triangle"), - pytest.param(0, 0, 4, 0, 2, 8, 16, id="Isosceles triangle"), - pytest.param(0, 0, 3, 0, 1, 4, 6, id="Scalene triangle"), - pytest.param(0, 0, -3, 0, 0, -4, 6, id="Negative values") - ] + ("p1x, p1y, p2x, p2y, p3x, p3y, expected"), + [ + pytest.param(0, 0, 2, 0, 1, 1.7320, 6, id="Equilateral triangle"), + pytest.param(0, 0, 3, 0, 0, 4, 6, id="Right-angled triangle"), + pytest.param(0, 0, 4, 0, 2, 8, 16, id="Isosceles triangle"), + pytest.param(0, 0, 3, 0, 1, 4, 6, id="Scalene triangle"), + pytest.param(0, 0, -3, 0, 0, -4, 6, id="Negative values") + ] ) def test_calculate_area(p1x, p1y, p2x, p2y, p3x, p3y, expected): - p1 = Point(p1x, p1y) - p2 = Point(p2x, p2y) - p3 = Point(p3x, p3y) - t = Triangle(p1, p2, p3) - assert t.calculate_area() == expected + p1 = Point(p1x, p1y) + p2 = Point(p2x, p2y) + p3 = Point(p3x, p3y) + t = Triangle(p1, p2, p3) + assert t.calculate_area() == expected ``` Let's have a look at how this works. @@ -150,7 +150,6 @@ def is_prime(n: int) -> bool: if n % i == 0: return False return True - ``` :::::::::::::::::::::::: solution @@ -159,37 +158,37 @@ def is_prime(n: int) -> bool: import pytest @pytest.mark.parametrize( - ("n, expected"), - [ - pytest.param(0, False, id="0 is not prime"), - pytest.param(1, False, id="1 is not prime"), - pytest.param(2, True, id="2 is prime"), - pytest.param(3, True, id="3 is prime"), - pytest.param(4, False, id="4 is not prime"), - pytest.param(5, True, id="5 is prime"), - pytest.param(6, False, id="6 is not prime"), - pytest.param(7, True, id="7 is prime"), - pytest.param(8, False, id="8 is not prime"), - pytest.param(9, False, id="9 is not prime"), - pytest.param(10, False, id="10 is not prime"), - pytest.param(11, True, id="11 is prime"), - pytest.param(12, False, id="12 is not prime"), - pytest.param(13, True, id="13 is prime"), - pytest.param(14, False, id="14 is not prime"), - pytest.param(15, False, id="15 is not prime"), - pytest.param(16, False, id="16 is not prime"), - pytest.param(17, True, id="17 is prime"), - pytest.param(18, False, id="18 is not prime"), - pytest.param(19, True, id="19 is prime"), - pytest.param(20, False, id="20 is not prime"), - pytest.param(21, False, id="21 is not prime"), - pytest.param(22, False, id="22 is not prime"), - pytest.param(23, True, id="23 is prime"), - pytest.param(24, False, id="24 is not prime"), - ] + ("n, expected"), + [ + pytest.param(0, False, id="0 is not prime"), + pytest.param(1, False, id="1 is not prime"), + pytest.param(2, True, id="2 is prime"), + pytest.param(3, True, id="3 is prime"), + pytest.param(4, False, id="4 is not prime"), + pytest.param(5, True, id="5 is prime"), + pytest.param(6, False, id="6 is not prime"), + pytest.param(7, True, id="7 is prime"), + pytest.param(8, False, id="8 is not prime"), + pytest.param(9, False, id="9 is not prime"), + pytest.param(10, False, id="10 is not prime"), + pytest.param(11, True, id="11 is prime"), + pytest.param(12, False, id="12 is not prime"), + pytest.param(13, True, id="13 is prime"), + pytest.param(14, False, id="14 is not prime"), + pytest.param(15, False, id="15 is not prime"), + pytest.param(16, False, id="16 is not prime"), + pytest.param(17, True, id="17 is prime"), + pytest.param(18, False, id="18 is not prime"), + pytest.param(19, True, id="19 is prime"), + pytest.param(20, False, id="20 is not prime"), + pytest.param(21, False, id="21 is not prime"), + pytest.param(22, False, id="22 is not prime"), + pytest.param(23, True, id="23 is prime"), + pytest.param(24, False, id="24 is not prime"), + ] ) def test_is_prime(n, expected): - assert is_prime(n) == expected + assert is_prime(n) == expected ``` :::::::::::::::::::::::::::::::::