Writing test cases in Blockchain / Solidity - Time & Space Complexity
When writing test cases for blockchain code, it's important to know how the time to run tests grows as you add more cases.
We want to understand how the number of tests affects the total time needed to check the code.
Analyze the time complexity of the following test-running code snippet.
function runTests(tests) {
for (let i = 0; i < tests.length; i++) {
tests[i].execute();
}
}
This code runs each test case one by one from a list of tests.
Look for loops or repeated actions.
- Primary operation: Calling
execute()on each test case. - How many times: Once for each test in the list.
As you add more tests, the total time grows in a simple way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 calls to execute() |
| 100 | 100 calls to execute() |
| 1000 | 1000 calls to execute() |
Pattern observation: The total work grows directly with the number of tests.
Time Complexity: O(n)
This means if you double the number of tests, the total time to run them roughly doubles.
[X] Wrong: "Running more tests doesn't affect total time much because each test is small."
[OK] Correct: Even if each test is quick, running many tests adds up, so total time grows with the number of tests.
Understanding how test time grows helps you write efficient tests and shows you can think about code quality and maintenance.
"What if each test case itself runs a loop over data of size m? How would the time complexity change?"
Practice
Solution
Step 1: Understand the role of test cases
Test cases are written to check if the code works correctly and to catch mistakes early.Step 2: Relate to blockchain deployment
Since blockchain contracts are hard to change after deployment, testing helps avoid costly errors.Final Answer:
To find and fix errors before deploying the contract -> Option AQuick Check:
Test cases catch errors early = C [OK]
- Thinking tests speed up contract execution
- Believing tests increase gas cost intentionally
- Assuming tests make code longer for no reason
Solution
Step 1: Recall common test grouping syntax
In Mocha and similar frameworks,describeis used to group related tests.Step 2: Identify correct function name
Onlydescribeis the standard function for grouping; others are incorrect or do not exist.Final Answer:
describe('Token tests', () => { /* tests */ }) -> Option DQuick Check:
Group tests with describe() = A [OK]
- Using group() instead of describe()
- Confusing it() with describe()
- Inventing non-existent functions like testGroup()
it('should store the value correctly', async () => {
await contract.store(42);
const result = await contract.retrieve();
assert.equal(result.toNumber(), 42);
});
What will be the output if the contract stores 42 correctly?Solution
Step 1: Analyze the test steps
The test callsstore(42)then retrieves the value and checks if it equals 42.Step 2: Understand assertion behavior
If the contract works correctly,result.toNumber()will be 42, soassert.equalpasses without error.Final Answer:
Test passes with no errors -> Option AQuick Check:
Correct value stored means test passes = A [OK]
- Assuming test fails even if values match
- Confusing syntax errors with assertion failures
- Ignoring async/await usage in tests
it('should transfer tokens', async () => {
await contract.transfer(receiver, 100);
const balance = await contract.balanceOf(receiver);
assert.equal(balance, 100);
});Solution
Step 1: Check async calls and returns
ThebalanceOflikely returns a BigNumber object, not a plain number.Step 2: Verify assertion correctness
Comparingbalancedirectly to 100 fails because types differ; conversion to number is needed.Final Answer:
Incorrect assertion comparing balance object to number -> Option CQuick Check:
Compare values with matching types = D [OK]
- Forgetting to convert BigNumber to number
- Assuming balanceOf returns a plain number
- Missing await on async calls
Solution
Step 1: Understand test goal
The test should verify that unauthorized users cannot change ownership.Step 2: Choose test action
CallingchangeOwnerfrom a non-owner account and expecting an error confirms access control works.Step 3: Eliminate wrong options
Testing with owner account or no account does not check unauthorized rejection; skipping test misses bugs.Final Answer:
Call the changeOwner function from an unauthorized account and expect an error -> Option BQuick Check:
Test unauthorized access by expecting failure = B [OK]
- Testing only authorized calls
- Ignoring unauthorized access tests
- Assuming blockchain prevents all unauthorized actions
Ready to prove it?
Pass the test and this pattern moves unknown
