270 likes | 421 Views
Test Driven Lasse Koskela Chapter 4: Concepts and Patterns for TDD. Paul Ammann http://cs.gmu.edu/~pammann/. Overview. How to Write Tests and Make Them Pass Essential Testing Concepts Closer Look into Test Doubles Guidelines for Testable Designs Unit-Testing Patterns
E N D
Test DrivenLasseKoskelaChapter 4: Concepts and Patterns for TDD Paul Ammann http://cs.gmu.edu/~pammann/
Overview • How to Write Tests and Make Them Pass • Essential Testing Concepts • Closer Look into Test Doubles • Guidelines for Testable Designs • Unit-Testing Patterns • Working With Legacy Code Lots of Stuff in This Chapter
How to Write Tests And Make Them Pass • Test Selection Strategies • Details-First vs. Big-Picture • Details-First Offers Concrete Progress, but • Big-Picture Fleshes Out Overall Design • Judgment Call In Any Given Situation • Uncertain vs. Familiar • Attacking Uncertainty Can Reduce Risk • Familiar Code May Have Large Payoff • High Value vs. Low Hanging Fruit • Usually, High Value is Better • Happy Path vs. Error Situations • Happy Path First – Mostly for Value • Sometimes Error Situations Help Define Remainder as Happy Path Keep Your Options in Mind; Avoid a Rut
How to Write Tests And Make Them Pass(2) • Implementation Strategies • Faking It • Useful Strategy For Handling Big Steps • Incurs Later Obligations To Squeeze Out Fakes • Triangulation • Strategy For Evolving Towards More General Implementation • Use To Drive Out Hard Coded Solutions • Obvious Implementation • Sometimes The Correct Solution Really Is Simple • Try It And See • If Tests Fail, Back It Out Goal Is To Get To Green Fast
How to Write Tests And Make Them Pass(3) • Prime Guidelines for Test Driving • Do. Not. Skip. Refactoring. • The Design Cycle for TDD is Crucial • Skipping This Step Leads to Code/Test Bloat • Result Is Unmaintainable Software • Get To Green Fast • Write Code That Passes The Tests First • Then Worry About Refactoring • Slow Down After a Mistake • Mistakes Indicate That Your Reach Exceeds Your Grasp • Back Off and Try Smaller Steps • The Tests Are The Oracle That Keeps You On Track The First Rule Is The Most Important
Essential Testing Concepts • Fixtures are the Context for Tests • Holistic View of State • Fixtures Remove Duplication • Bloated Tests Are Hard to Read and Hard to Maintain • Fixtures Allow For Focused Tests • Test Doubles Stand In for Dependencies • Example: java.sql.ResultSet • Details Depend on Database Used • More on Doubles in Later Slides Real-World JUnit Tests Can’t Avoid Some Complexities
Essential Testing Concepts(2) • State and Interaction-Based Testing • State-Based Testing • Idea Is To Look At Variable State To Verifying Result @Test public void notEmpty() { Collection<String> c = new ArrayList<String>(); assertTrue (c.isEmpty()); c.add(“Bob”); assertFalse(c.isEmpty()); } • Testing For Interactions • Goal: Did The Expected Methods Calls Happen In The Right Order? • Usually Requires Some Sort of Double We lean on interaction-based testing to verify how an object talks to its collaborators; we lean on state-based testing to verify how well the object listens.
Closer Look Into Test Doubles • Replace Object with Double If Real Object is • Too Slow • It’s Not Available • It Depends on Something That’s Not Available • Its Too Difficult To Instantiate Or Configure For a Test • Examples • How to test exceptions, such as • “Dead”code? • An unplugged network cable? • How to interact with something that’s nondeterministic? Doubles Are Key To Unit Testing
Closer Look Into Test Doubles(2) • Example of a Test Double • Next Slide • Stubs, Fakes, and Mocks • Stub: Simplest Possible Implementation • Fake: Still Hand Coded, But A Degree More Sophisticated • Mock: Usually Generated By Tools • Mock Objects in Action • Next slide Checking Correct Behavior is Complicated!
Guidelines for Testable Designs • Choose Composition Over Inheritance • General Advice For Normal Coding And Testing • More Verbose, But Worth It • Avoid Static and Singleton • These Are Hard To Double • Static class names are hardcoded. How to replace at test time? • This Can Conflict With Normal Coding Advice • Consider Factories! Test Requirements Impact Code!
4.4. Code smell: methods obtaining dependencies through static method calls Dependency Example: Static Method
Injecting Dependencies: Easy Test! public class OrderProcessorTest { @Test public void testOrderProcessorWithDependencyInjection() throws Exception { OrderProcessor p = new OrderProcessor(); p.setPricingService(new FakePricingService()); ... }}
Unit Testing Patterns • Assertion Patterns • Resulting State Assertion • Most Common Usage • Guard Assertion • Test Both Before and After The Action (precondition testing) • Delta Assertion • Verify Part of the State – Eg, List is One Bigger Than Before • Custom Assertion • Encodes Complex Verification Rules • Interaction Assertion • Verification For Interaction Tests Choose and Use Standard Patterns
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: Conventional JUnit Example
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: jMock Version
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: EasyMock Example
Fowler/Meszaros “Double” Definitions • A Test Double is anything that stands in for a real object • Dummy • Used to fill parameter lists • Fake • Actual working implementations, but take shortcuts • Example: In Memory Database • Stub • Canned answers to calls made during tests, but useless elsewhere • Mock • Objects preprogrammed with expectations that form a specification of the calls they expect to receive Various Levels of Complexity
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: Stub Example
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: Mock Version
Unit Testing Patterns (2) • Fixture Patterns • Parameterized Creation Method • Populating Complex Set Of Objects • Object Mother • Aggregate of Creation Methods • Automated TearDown • More Important For Integration Testing Than Unit Testing Fixtures Need Attention Too
Unit Testing Patterns (3) • Test Patterns • Parameterized Test (see next slide) • Self Shunt • The Double Is The Test Class • Intimate Inner Class • Sharing Between Test Class and Test Double Classes • Privileged Access • Reflection-Based Injection Approaches For Legacy Code (Careful) • Extra Constructor • Compensates For Classes Not Designed For Testing Tests Need To Accommodate A Variety of Real Code
Working With Legacy Code • Test-Driven Legacy Development • Analyzing the Change • Change Points and Inflection Points • Change Code at Change Points • See Effects At Inflection Points • Hopefully, The Points Are Close Together… • Preparing for the Change • Install Tests To Capture Current Behavior of Inflection Point • Test-Driving the Change • Add Tests To Capture New Behavior, Also At Inflection Point Turning Legacy Code Into TDD Code