My Testing Experience
Before my days of automated testing…
There’s no time for tests!
So what brought me to automated testing?
Everyday, I’m struggling!
Automated Testing Benefits
- Discover problems upfront
- Eases refactoring
- Tests are documentation
- Helps identify bad design
- Reduce regression bugs
- Reduce code change fears!
Writing Proper Tests
- A test should have clear and simple goals
- A test should be deterministic
- A test should test the right thing
Make Them With Simple Goals
Why?
- Easy to understand
- Easy to verify
- Easy to write
- Easy to maintain
Problem?
- Requirements are hard to get
- Hard to make tests simple with complex code
Make Them Deterministic
Why?
- Unpredictability = hard to test
Problem?
- Unable to inject dependencies
- Time
- External services
- State
Make Them Test The Right Thing
What not to do
- Don’t test code you don’t understand
- Do not test 3rd party libs/apis
- Spend less time on impossible cases
What to do
- Ensure correctness!
- Start clean for each test
- Test core behavior
- Mock 3rd party libs/apis
- Make tests portable
How to Start?
- Focus on testing the most important parts of your code.
- When you encounter a bug, write a test for it.
- When you’re unsure of what happening in code, write a test to explain it.
- When short on time, work more on end-to-end tests.
- When you have plenty of time, work more on unit tests.
- When you have free time, write any test.
Simple Example: Fibonacci in C++
Code:
int fib(int n) {
if (n <= 0) { return 0; }
else if (n == 1) { return 1; }
else { return fib(n-2) + fib(n-1); }
}
void main() {
cout << fib(5) << endl;
}
Test:
void testFib() {
// given
int n = 6;
// when
int x = fib(n);
// then
assert(x, 8);
}
Hard to Test Example
public class EntityController {
IRepo repo = new EntityRepo(...);
public Entity find(int id) {
Date d = Date.now();
if (d.getTime() % 60000 >= 30000) {
return repo.getEntity(id, d);
} else {
return null;
}
}
}
Less Hard to Test Example
public class EntityController {
private IRepo repo;
// we can perform dependency injection
public IRepo setRepo(IRepo r) {
repo = r;
}
// we can maintain backwards compatibility
public Entity find(int id) {
return find(id, Date.now());
}
// ... and still test deterministically
public Entity find(int id, Date d) {
if (d.getTime() % 60000 >= 30000) {
return repo.getEntity(id, d);
} else {
return null;
}
}
}
How I Feel About Tests Now
- I cannot live without some form of automated testing.
- Testing consumes a lot of time. Automating testing consumes a lot of time upfront, but pays off in the long run.
- It’s hard to write good tests.
- Automated tests are useful until you discover that you’re doing it all wrong.
- You must fix your tests as soon as they break.
- Don’t stop writing automated tests until you have confidence in your test suite.
- Make sure the tests run in a reasonable amount of time.