Advanced TDD
THE THREE LAWS OF TEST DRIVEN DEVELOPMENT
ARBITRARY DISCIPLINE
Like a surgeon scrubbing for surgery
Like a pilot following a checklist
THE FIRST LAW
You are not allowed to write any production code until you have written a unit test that fails due to its absence.
THE SECOND LAW
You are not allowed to write more of a unit test than is sufficient to fail, and not compiling is failing.
THE THIRD LAW
You are not allowed to write more production code than is sufficient to pass the currently failing test to pass.
THE CODE EXAMPLES
Have you integrated a third party package.
You read the code examples, not the manual.
Unit tests are the code examples for the whole system
DOCUMENTS!
Written in a language you understand.
Utterly unambiguous.
So formal they execute.
They cannot get out of sync with the application.
Easy to understand. Not a system.
TEST AFTER THE FACT?
Boring
You've already tested manually.
The function that's hard to test...
Leave a hole in the test suite.
And fi you do it...
Do you shrug when your tests pass?
TEST FIRST
Fun. You make it work!
You can't write the function that's hard to test.
System is testable.
System is decoupled.
You trust the tests!
OBJECTIONS HEARD (BUT NOT BELIEVED)
"I know how to just write the class, but don't know how to test it."
"We have to write twice as much code and provide two people to do it."
"I have to debug twice as much code."
"We have a testing department."
"I can test my code after I write it."
PROFESSIONALISM RANT.
Laborers take orders.
Professionals "Profess"
Hired for knowledge and expertise
Managers will push, and want pushback.
Professionals push back.
WHO ELSE HAS OUR PROBLEM
We produce complex documents full of arcane symbols.
Must be correct or terrible things happen.
ACCOUNTANTS!
The right digit, in the right place, at the right time...
Brings the company down and sends the executives to jail.
HOW DO ACCOUNTANTS PREVENT THIS?
They have a discipline.
500 years old.
Double Entry Bookkeeping.
DOUBLE ENTRY BOOK KEEPING.
Every transaction is entered twice.
Once under Assets. Once under Liabilities and Equities.
The two sides are summed.
The sums are subtracted on the balance sheet.
The result must be zero.
THE PROCEDURE
Accountants are taught to enter transactions one at a time.
For obvious reasons.
TDD IS DOUBLE ENTRY BOOKKEEPING.
The practices are the same.
They are done for the same reason.
Every behavior is entered twice.
Once as a test, again as production code.
The two entries must agree.
IF ACCOUNTANTS CAN DO IT...
Accountants have schedules and deadlines just like us.
Our documents are not less important than the accountant's
If they can do it...
CLEAN TESTS
WHAT DOES THIS TEST DO?
PROBLEMS WITH THIS TEST.
More than one logical assert
Accidental Complexity(
getScannedResults()
.getTable(0)
)Too Slow
Wide Scope
Colloquialisms
BETTER TESTs
One Logical Assert
No Accidental Complexity
Fast
Narrow Scope
Meaningful Values
COMPOSED ASSERTION
Changes many asserts into one.
Hides accidental complexity.
COMPOSED TEST RESULT
A test result that merges many variables into one.
e.g. Booleans into an integer or a string.
Human interpretation should be simple.
Changes many asserts into one
STUBBING VS MOCKING TESTING BEHAVIOR VS STATE
Test Doubles
Dummy: Do nothing. Return degenerate values.
public interface Authenticator { Boolean authenticate(String username, String password); } public class AuthenticatorStub implements Authenticator { public Boolean authenticate(String username, String password) { return null; } }STUBS: A dummy that returns Test Specific Values.
public class RejectingAuthenticatorStub implements Authenticator { public Boolean authenticate (String username, String password) { return false; } } public class PromiscuousAuthenticatorStub implements Authenticator { public Boolean authenticate (String username, String password) { return true; } }SPIES: Stub that remembers facts about the method calls.
МОСК: Spy that knows how methods should be called.
FAKE: A Simple Simulator.
THE TDD UNCERTAINTY PRINCIPLE
Testing State leaves you uncertain that all answers will be correct.
Mocking provides certainty but leads to Fragile Tests.
Fragility increases with certainty.
WISDOM
Avoid Test Doubles except when crossing architectural boundaries.
Avoid Mocking tools unless you need superpowers.
F.I.R.S.T Principles
Fast: test runs < 1 second.
DB, Web Container Isolation
Isolated: fault is clearly isolated
Tests do not depend upon each other. Each tests can stand alone.
Tests can be run in any order.
Junit does not guarantee order.
Be careful of static variables.
Repeatable: constant behavior
Tests should not be dependent upon environmental issues.
Should run the same in the lab, and at 30,000 feet over the Atlantic.
Never subject to network timing, memory usage, other processes, etc.
There should never be an excuse for a failure.
외부 요인에 영향을 받지 않아야 함
Self-verifying: pass or fail
The test has a binary result. Pass/ Fail.
No interpretation is required.
Timely: 1 code change = 1 test
Tests are written first, before the code that passes them. (most of the time).
THE REAL MEANING OF "FIRST"
The Tests Come First.
They are written first.
They are refactored first.
They are higher priority than the application code.
Because without the tests
The code must rot.
테스트 설계
DECOUPLE TESTS FROM APPLICATION CODE
• Otherwise the tests become fragile. • Al the same principles apply. • Use a testing API to isolate the tests from the code. • Do not allow the tests to be too intimate with the code.
DECOUPLE THE STRUCTURE
Do not create a test class for each production class!
This couples the structure and creates fragility.
ADD TESTS, BUT EXTRACT FUNCTIONS AND CLASSES.
TEST PATTERNS
TEST SPECIFIC SUBCLASS
SELF-SHUNT
HUMBLE OBJECT
TEST CONVENTIONS
TEST NAMES
The WHEN_THEN convention
unboundSymbol_notReplaced
boundSymbol_replaced
nullBuffer_noAction
nullSymbol_noAction
TESTING PRIVATE OR PROTECTED METHODS
Principle #1: Don't Test Private or Protected Methods.
Test public and extract private and protected methods.
Extracted methods are already tested.
Principle #2: Testing Trumps Privacy
fI you have a private method that needs testing, make it protected and put the test in the same package.
Or, better yet, extract the private method into it's own class where it can be public.
Principle #3: Testing privates implies a design error.
You can't test through public interface.
Therefore private method does more than public can ask
HIERARCHICAL TESTS
Junit: HierarchicalContextRunner
COVERAGE AND METRICS
COVERAGE
Goal is 100%
Asymptotic
FitNesse is at 90% (Probably more)
Coverage should be measured, plotted, and visible
Everyone should see the current test coverage numbers
Coverage should not be mandated
Leads ot false positives, e.g. "no asserts"
Tests should be regularly reviewed
To make sure they assert what is covered
MUTATION TESTING
pitest.org.
Tool runs coverage. Sees tests pass.
Tool makes one semantic mutation (byte code)
Re-runs tests and coverage.
Marks mutation as "living" fi tests pass.
Repeat for all possible semantic mutations.
Finds all unasserted code.
BEHAVIOR DRIVEN DEVELOPMENT
BDD is TDD with an emphasis on Readability
GUI TESTING
Humble Object
눈으로 확인
하지만 가끔 GUI 테스트가 필요함
TESTING THROUGH THE GUI
Couples the tests to the GUI.
TEST BUSINESS RULES THROUGH THE API
Decouple the tests from the GUI.
GUI TESTS TEST ONLY GUI
¡
Stub out the application to prevent testing business rules.
TESTING LEVELS
LEVELS OF TESTING.
LEGACY CODE
GETTING LEGACY CODE UNDER TEST.
No Magic Bullet.
Took years to make the mess.
Will take a long time to undo it.
Don't tackle as a single huge project.
Use the 'Boy Scout Rule'
CONVINCING
HOW DO I CONVINCE...
You can't force people to believe.
You can be a role model.
You can exhort and encourage.
You can give demos.
You will convince some.
But not others.
Divorce.