Writing basic test functions in Go - Time & Space Complexity
When writing basic test functions in Go, it is important to understand how the time taken grows as tests run on more cases.
We want to know how the number of tests affects the total time to complete all tests.
Analyze the time complexity of the following code snippet.
func TestSum(t *testing.T) {
for i := 0; i < len(testCases); i++ {
got := Sum(testCases[i].input)
if got != testCases[i].expected {
t.Errorf("Sum() = %d; want %d", got, testCases[i].expected)
}
}
}
This test function runs through a list of test cases and checks if the Sum function returns the expected result for each.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each test case once.
- How many times: Exactly once per test case in the list.
As the number of test cases grows, the total time grows in direct proportion.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 checks |
| 100 | 100 checks |
| 1000 | 1000 checks |
Pattern observation: Doubling the number of test cases roughly doubles the total work done.
Time Complexity: O(n)
This means the time to run all tests grows linearly with the number of test cases.
[X] Wrong: "Running more tests won't affect total time much because each test is small."
[OK] Correct: Even small tests add up, so more tests mean more total time in a straight line.
Understanding how test functions scale helps you write efficient tests and reason about testing time in real projects.
What if we added nested loops inside each test case? How would the time complexity change?
Practice
Solution
Step 1: Understand Go test function naming
Test functions must start with 'Test' and take a '*testing.T' parameter.Step 2: Check each option
Only func TestExample(t *testing.T) {} matches the required signature and naming convention.Final Answer:
func TestExample(t *testing.T) {} -> Option AQuick Check:
Test function starts with 'Test' and uses '*testing.T' [OK]
- Not starting function name with 'Test'
- Missing '*testing.T' parameter
- Using lowercase 'test' prefix
Solution
Step 1: Understand failure reporting methods
Both t.Error and t.Fatal report failures, but t.Error reports and continues, t.Fatal stops immediately.Step 2: Identify the correct method for reporting failure
t.Error is commonly used to report a failure without stopping the test immediately.Final Answer:
t.Error("failure message") -> Option BQuick Check:
Use t.Error to report failure inside tests [OK]
- Using t.Log which only logs info
- Using t.Fail without message
- Confusing t.Fatal with t.Error
go test?
func TestSum(t *testing.T) {
total := 2 + 2
if total != 4 {
t.Error("Sum is incorrect")
}
}Solution
Step 1: Analyze the test logic
The sum 2 + 2 equals 4, so the condition 'total != 4' is false and t.Error is not called.Step 2: Understand test output behavior
Since no error is reported, the test passes silently with no failure message.Final Answer:
Test passes with no output -> Option CQuick Check:
Correct sum means no error reported [OK]
- Assuming test fails when condition is false
- Confusing test output with print statements
- Thinking syntax error exists when code is correct
func TestCheck(t *testing.T) {
if 1 == 1 {
t.Error("Test failed")
}
}Solution
Step 1: Analyze the condition inside the test
The condition '1 == 1' is always true, so t.Error is always called.Step 2: Understand test failure consequence
Because t.Error is called unconditionally, the test always fails, which is likely a logic error.Final Answer:
The test always fails because condition is always true -> Option AQuick Check:
Always true condition causes test failure [OK]
- Ignoring always true condition
- Confusing t.Error and t.Fail usage
- Overlooking function naming correctness
Multiply(a, b int) int returns the correct product. Which test function correctly tests this with failure reporting?Solution
Step 1: Check function signature and parameter
Test functions must have signature func TestX(t *testing.T). Only options B, C, and D have this.Step 2: Verify test logic correctness
func TestMultiply(t *testing.T) { if Multiply(3, 4) != 12 { t.Error("Expected 12") } } checks if Multiply(3,4) != 12 and reports error if true, which is correct. func TestMultiply(t *testing.T) { if Multiply(3, 4) == 12 { t.Error("Expected 12") } } wrongly reports error if result equals 12. func TestMultiply(t *testing.T) { if Multiply(3, 4) != 7 { t.Error("Expected 7") } } expects 7, which is incorrect.Final Answer:
func TestMultiply(t *testing.T) { if Multiply(3, 4) != 12 { t.Error("Expected 12") } } -> Option DQuick Check:
Correct signature and logic test for Multiply [OK]
- Missing *testing.T parameter
- Wrong expected value in condition
- Inverted condition causing false failures
Ready to prove it?
Pass the test and this pattern moves unknown
