Regression testing in Software Engineering - Time & Space Complexity
When studying regression testing, it is important to understand how the time to run a test suite grows as the codebase and number of tests increase.
We want to know how test execution scales and why test selection strategies matter.
Analyze the time complexity of running a full regression test suite versus a selective suite.
Full regression:
for each test_case in all_tests:
setup test environment
execute test
compare actual vs expected result
record pass/fail
Selective regression:
affected_modules = analyze_dependencies(changed_files)
for each test_case in all_tests:
if test_case.module in affected_modules:
execute test
Full regression runs every test. Selective regression uses dependency analysis to run only relevant tests.
Look at what repeats in each approach.
- Full regression: Every test case is executed regardless of the change. The loop runs n times for n total tests.
- Selective regression: Dependency analysis runs once, then only tests mapped to affected modules execute — typically a fraction of n.
As the project grows, the test suite grows with it.
| Total Tests (n) | Full Regression | Selective (20% affected) |
|---|---|---|
| 100 tests | 100 executed | ~20 executed |
| 1,000 tests | 1,000 executed | ~200 executed |
| 10,000 tests | 10,000 executed | ~2,000 executed |
Pattern observation: Full regression is O(n) — every test runs. Selective regression is also O(n) for the filtering step but executes only O(k) tests where k is the number of affected tests, typically k << n.
Full Regression: O(n) where n is the total number of test cases
Selective Regression: O(n + k) — O(n) to filter, O(k) to execute, where k is tests for affected modules
In practice, selective regression saves significant time because k is much smaller than n for localized changes.
[X] Wrong: "We only need to test the code we changed, not anything else."
[OK] Correct: Changes in one module can break dependent modules. Regression testing must cover not just the changed code but all code that depends on it. This is why dependency analysis in selective regression includes affected modules, not just changed files.
Understanding regression testing complexity helps explain CI/CD pipeline design decisions. Knowing when to use full vs selective regression is a common interview topic in QA and DevOps discussions.
If a project has 10,000 tests and average test execution takes 2 seconds, how long does a full regression run take? How would test parallelization across 10 machines change this?
Practice
regression testing in software development?Solution
Step 1: Understand regression testing goal
Regression testing is done to ensure that recent code changes do not negatively affect existing functionality.Step 2: Match purpose with options
To check that new code changes do not break existing features clearly states this purpose, while others focus on performance, security, or design, which are different testing types.Final Answer:
To check that new code changes do not break existing features -> Option AQuick Check:
Regression testing = check existing features still work [OK]
- Confusing regression testing with performance testing
- Thinking regression testing finds new bugs only
- Mixing regression testing with security testing
Solution
Step 1: Identify automation in regression testing
Automated regression tests are scripts that run automatically to check software after changes.Step 2: Compare options to automation definition
A script that runs tests automatically after code changes matches this exactly. Others describe manual or unrelated activities.Final Answer:
A script that runs tests automatically after code changes -> Option AQuick Check:
Automated regression test = automatic script [OK]
- Confusing manual checks with automated tests
- Thinking reports or documents are tests
- Ignoring the 'automatic' part of regression testing
def test_model_accuracy(model, test_data, expected_accuracy):
accuracy = model.evaluate(test_data)
return accuracy >= expected_accuracy
class DummyModel:
def evaluate(self, data):
return 0.85
model = DummyModel()
result = test_model_accuracy(model, None, 0.80)
print(result)What will be the output when this code runs?
Solution
Step 1: Understand the evaluate method output
The DummyModel's evaluate method returns 0.85 regardless of input.Step 2: Check the comparison in test_model_accuracy
It compares 0.85 >= 0.80, which is True, so the function returns True.Final Answer:
True -> Option CQuick Check:
0.85 >= 0.80 = True [OK]
- Assuming None input causes error
- Confusing returned accuracy with boolean result
- Ignoring the fixed return value of evaluate
def run_regression_tests(tests):
for test in tests:
if not test():
print("Test failed")
break
else:
print("All tests passed")
def test1():
return True
def test2():
return False
run_regression_tests([test1, test2])What is the output of this code?
Solution
Step 1: Analyze the loop over tests
The loop runs test1() which returns True, so continues to test2().Step 2: Check test2() result and loop behavior
test2() returns False, triggering print("Test failed") and break to exit loop.Final Answer:
Test failed -> Option BQuick Check:
Second test fails, loop breaks, prints 'Test failed' [OK]
- Thinking else after for runs always
- Ignoring break statement effect
- Assuming all tests run regardless of failure
Solution
Step 1: Identify best regression testing practice for ML models
Automated tests on a fixed test set ensure consistent checks after updates.Step 2: Evaluate options for reliability
Run automated tests comparing model predictions on a fixed test set before and after updates uses automation and fixed data, catching errors reliably. Others rely on manual or reactive methods, which are less reliable.Final Answer:
Run automated tests comparing model predictions on a fixed test set before and after updates -> Option DQuick Check:
Automated fixed tests catch errors best [OK]
- Relying on manual checks only
- Ignoring testing until errors reported
- Assuming lower training loss means no bugs
Ready to prove it?
Pass the test and this pattern moves unknown
