如何测试比较操作合规使用,避免学生直接赋值布尔值作弊?
Got it, let's break down how to verify students are using actual comparison operations (like id(x) == id(y)) instead of cheating by hardcoding is_identical = True or False directly. Since you're running unit/pytests and aren't using functions yet, here are practical, actionable approaches:
1. Inspect the Code's Abstract Syntax Tree (AST)
Python's built-in ast module lets you analyze the structure of code without executing it. This is the most reliable way to confirm the assignment to is_identical uses a comparison expression rather than a hardcoded boolean.
You can write a pytest test that parses the student's script, looks for the is_identical assignment, and checks if its right-hand side is a comparison node:
import ast def test_used_comparison_operation(): # Load the student's code file with open("student_assignment.py", "r") as f: code_content = f.read() # Parse the code into an AST tree tree = ast.parse(code_content) valid_assignment_found = False for node in ast.walk(tree): # Look for assignment statements targeting "is_identical" if isinstance(node, ast.Assign): for target in node.targets: if isinstance(target, ast.Name) and target.id == "is_identical": # Verify the right-hand side is a comparison (e.g., a == b, id(x) != id(y)) if isinstance(node.value, ast.Compare): valid_assignment_found = True else: assert False, "Error: You must use a comparison operation to set is_identical (e.g., id(x) == id(y))!" assert valid_assignment_found, "Error: No valid assignment to is_identical using a comparison was found!"
This will catch any direct boolean assignments immediately, as they'll show up as ast.Constant nodes instead of ast.Compare nodes.
2. Test with Multiple Input Case Variations
Hardcoded boolean values will fail when tested against different input pairs where the expected result changes. You can create parametrized tests that run the student's code with various x and y values, ensuring the result adapts correctly.
Here's how to implement this in pytest:
import pytest import importlib.util def load_student_module(): # Dynamically load the student's script as a module spec = importlib.util.spec_from_file_location("student_code", "student_assignment.py") student_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(student_module) return student_module @pytest.mark.parametrize("x_val, y_val, expected_result", [ (42, 42, True), # Same integer value (should be identical) (42, 43, False), # Different integers ("hello", "hello", True), # Interned string (identical) ([1,2], [1,2], False), # Lists with same content (different objects) ]) def test_dynamic_input_cases(x_val, y_val, expected_result): student_module = load_student_module() # Override x and y in the student's module student_module.x = x_val student_module.y = y_val # Re-execute the assignment logic (since it's top-level code) exec(open("student_assignment.py").read(), student_module.__dict__) assert student_module.is_identical == expected_result, \ f"Failed for x={x_val}, y={y_val}: Expected {expected_result} but got {student_module.is_identical}"
If a student hardcodes is_identical, at least one of these test cases will fail, exposing the cheat.
3. Basic String Pattern Check (Quick Guardrail)
While not foolproof (students can obfuscate code), adding a simple check for comparison operators can catch obvious cheats quickly. You can verify the student's code contains operators like ==, !=, is, or is not:
def test_contains_comparison_operator(): with open("student_assignment.py", "r") as f: code_content = f.read() required_operators = ["==", "!=", "is", "is not"] has_valid_operator = any(op in code_content for op in required_operators) assert has_valid_operator, "Error: Your code must include a comparison operator (==, !=, is, is not)!"
Use this as a quick first check alongside the AST and multi-case tests for better coverage.
Combining these methods gives you a robust setup: the AST check enforces correct code structure, the multi-case tests validate logical correctness, and the string check catches lazy cheats right away.
内容的提问来源于stack exchange,提问作者colidyre

