python-test-updater — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited python-test-updater (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Update Python tests to work correctly with new code versions.
Gather required inputs:
Verify inputs:
Automated analysis:
python scripts/analyze_code_diff.py <old_file> <new_file>Manual analysis:
Identify change types:
Function signature changes:
Return value changes:
Behavior changes:
Class changes:
Async changes:
See test-update-patterns.md for detailed patterns.
Read the old tests:
Identify test components:
Map tests to code:
For each code change, identify test impact:
Signature changes → Update function calls
# Old code: function(arg1, arg2)
# New code: function(arg1, arg2, arg3=default)
# Old test
result = function(value1, value2)
# Updated test
result = function(value1, value2) # Works with default
# OR
result = function(value1, value2, value3) # Explicit valueReturn value changes → Update assertions
# Old code: return value
# New code: return {"result": value, "status": "ok"}
# Old test
assert result == expected_value
# Updated test
assert result["result"] == expected_value
assert result["status"] == "ok"Behavior changes → Update expected values
# Old code: validates length >= 6
# New code: validates length >= 8 and has digit
# Old test
assert validate("abc123") == True
# Updated test
assert validate("abc12345") == True # Updated
assert validate("abc123") == False # Now failsNew functionality → Add new tests
# New code: added get_display_name() method
# Add new test
def test_get_display_name():
obj = MyClass("value")
assert obj.get_display_name() == "Value: value"Apply updates systematically:
Step 1: Update imports if needed
# If new exceptions or classes added
from module import NewException, NewClassStep 2: Update function/method calls
Step 3: Update assertions
Step 4: Update exception handling
# Old
with pytest.raises(OldException):
function()
# New
with pytest.raises(NewException):
function()Step 5: Update async/await if needed
# Old
def test_function():
result = function()
# New (if function became async)
@pytest.mark.asyncio
async def test_function():
result = await function()Step 6: Add new test cases
Execute the updated tests:
# Run all tests
pytest test_file.py
# Run specific test
pytest test_file.py::test_function
# Run with verbose output
pytest -v test_file.pyCheck results:
If tests still fail:
Analyze error messages:
Common failure types:
1. AssertionError
AssertionError: assert 10 == 15→ Expected value changed, update assertion
2. TypeError
TypeError: function() missing 1 required positional argument: 'new_param'→ Add missing parameter to function call
3. AttributeError
AttributeError: 'dict' object has no attribute 'field'→ Return type changed, update how result is accessed
4. ImportError
ImportError: cannot import name 'OldClass'→ Class renamed or removed, update import
Fix each failure:
Final verification:
Refine if needed:
Example refinement:
# Before
def test_function_case1():
assert function(5) == 10
def test_function_case2():
assert function(10) == 20
# After (parametrized)
@pytest.mark.parametrize("input,expected", [
(5, 10),
(10, 20),
])
def test_function(input, expected):
assert function(input) == expectedCode change:
# Old
def function(a, b):
return a + b
# New
def function(a, b, c=0):
return a + b + cTest update:
# Old test (still works)
def test_function():
assert function(1, 2) == 3
# Add new test for new parameter
def test_function_with_c():
assert function(1, 2, 3) == 6Code change:
# Old
def get_data():
return [1, 2, 3]
# New
def get_data():
return {"data": [1, 2, 3], "count": 3}Test update:
# Old
def test_get_data():
data = get_data()
assert len(data) == 3
# New
def test_get_data():
result = get_data()
assert len(result["data"]) == 3
assert result["count"] == 3Code change:
# Old
def validate(value):
return len(value) >= 6
# New
def validate(value):
return len(value) >= 8 and any(c.isdigit() for c in value)Test update:
# Old
def test_validate():
assert validate("abc123") == True
assert validate("abc") == False
# New
def test_validate():
assert validate("abc12345") == True # Updated
assert validate("abc123") == False # Now fails validation
assert validate("abcdefgh") == False # No digit
assert validate("abc") == FalseCode change:
# Old
def fetch():
return data
# New
async def fetch():
return await async_data()Test update:
# Old
def test_fetch():
result = fetch()
assert result is not None
# New
@pytest.mark.asyncio
async def test_fetch():
result = await fetch()
assert result is not NoneSolution:
Solution:
Solution:
Solution:
Old code:
def calculate_price(quantity, unit_price):
return quantity * unit_priceNew code:
def calculate_price(quantity, unit_price, discount=0.0):
subtotal = quantity * unit_price
return subtotal * (1 - discount)Old test:
def test_calculate_price():
price = calculate_price(5, 10.0)
assert price == 50.0Analysis:
discount with default value 0.0Updated test:
def test_calculate_price():
# Test without discount (original behavior)
price = calculate_price(5, 10.0)
assert price == 50.0
def test_calculate_price_with_discount():
# Test with discount (new behavior)
price = calculate_price(5, 10.0, 0.1)
assert price == 45.0 # 50 * 0.9Verification:
pytest test_file.py -v
# Both tests should passProvide updated test code with:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.