如何在Python中编写更优质的多边形对象验证测试用例?
Great question! Let's build out a robust, maintainable set of test cases for your validate_object function. Using a framework like pytest (the de facto standard for Python testing), we can structure tests to cover all valid scenarios and every possible failure edge case—while keeping the code clean and easy to update.
First, Let's Structure Our Tests
We'll split tests into two core categories: valid inputs that should pass, and invalid inputs that should raise specific exceptions.
1. Test Valid Inputs
These cases confirm the function accepts correctly formatted polygons, including different sizes and winding orders.
import pytest from your_module import validate_object # Replace with your actual module name def test_valid_triangle_clockwise(): # 3-point clockwise triangle valid_obj = {"polygon": [(0, 0), (0, 10), (10, 0)]} validate_object(valid_obj) # Should not raise any exception def test_valid_rectangle_counterclockwise(): # 4-point counterclockwise rectangle valid_obj = {"polygon": [(0, 0), (10, 0), (10, 10), (0, 10)]} validate_object(valid_obj) def test_valid_large_convex_polygon(): # 5-point convex polygon (any valid winding order) valid_obj = {"polygon": [(0, 0), (5, 0), (7, 3), (3, 7), (0, 5)]} validate_object(valid_obj)
2. Test Invalid Inputs (Exception Cases)
We'll use pytest.mark.parametrize to batch-test all failure scenarios—this cuts down on redundant code and makes it trivial to add new cases later. Each entry targets one specific failure condition.
@pytest.mark.parametrize("invalid_input, expected_error_msg", [ # Non-dict input types ([], "dict type input required."), ("not a dictionary", "dict type input required."), (12345, "dict type input required."), # Missing 'polygon' key in dict ({}, "polygon object required."), ({"other_attribute": []}, "polygon object required."), # 'polygon' is not a list ({"polygon": "string instead of list"}, "list type polygon object required."), ({"polygon": {"key": "value"}}, "list type polygon object required."), ({"polygon": 6789}, "list type polygon object required."), # Polygon has fewer than 3 points ({"polygon": []}, "More than two points required."), ({"polygon": [(0, 0)]}, "More than two points required."), ({"polygon": [(0, 0), (10, 0)]}, "More than two points required."), # Point pairs contain non-integer values ({"polygon": [(0.5, 0), (0, 10), (10, 0)]}, "integer (x,y) pairs required."), ({"polygon": [("0", 0), (0, 10), (10, 0)]}, "integer (x,y) pairs required."), ]) def test_invalid_inputs(invalid_input, expected_error_msg): with pytest.raises(ValueError) as excinfo: validate_object(invalid_input) assert str(excinfo.value) == expected_error_msg
Why This Approach Is Better
- Full Coverage: We test every condition your validation function checks, plus edge cases like empty lists, single points, and non-standard value types.
- Maintainable: Parameterized tests mean adding a new failure scenario is as simple as adding one line to the test list—no need to write a whole new function.
- Clear Debugging: Each test focuses on one specific failure, so if a test fails, you immediately know exactly what condition broke.
- Readable: Anyone reviewing the tests can quickly grasp what counts as valid or invalid for the polygon object.
Bonus: Gap to Address
Your current function doesn't handle non-2-element "points" (like single-value tuples (0,) or 3-value tuples (0,0,1)) gracefully—it'll throw a TypeError instead of your custom ValueError. If you want to fix this, add a check for len(point) == 2 in the loop, then update the test cases to include scenarios like:
({"polygon": [(0,), (0,10), (10,0)]}, "integer (x,y) pairs required."), ({"polygon": [(0,0,1), (0,10), (10,0)]}, "integer (x,y) pairs required."),
内容的提问来源于stack exchange,提问作者user1609160

