Upload
brian-westrich
View
296
Download
0
Embed Size (px)
Citation preview
© 2015 McWest Corporation 1
Spock TDD
Tests as Assets not Afterthoughts
by Brian Westrich, McWest [email protected]
© 2015 McWest Corporation
About me• TDD developer since 1989• Minneapolis-based
• Consultant at McWest Corp. (www.mcwest.com)• Custom software design, development,
and mentoring• Historical focus: Java/Groovy• Increasing focus: JavaScript
• Recently consulted for large enterprise successfully using TDD
© 2015 McWest Corporation
Minneapolis development projects: Light-rail, Vikings stadium
© 2015 McWest Corporation 4
Agenda• History of TDD• Spock TDD case study• Spock tests as assets • Testing effectively• TDD in teams• TDD mantras• Summary / Conclusion• Resources
© 2015 McWest Corporation 5
History of TDD
© 2015 McWest Corporation 6
Timeframe? Automated dev tests are Developers say
Pre - 2000 a curiousity “Why is he testing?”
Early 2000s a threat “Don’t check that in.”
Mid 2000s a given “Good idea!”
Late 2000s an obsession “We need 100% coverage.”
2010 - now an obligation, an afterthought
“I’ve finished everything except the tests.”
Future? an asset? “My project needs tests, and I want to write them.”
© 2015 McWest Corporation 7
Presentation Goal• Help you create tests that are Assets not Afterthoughts.• Make you want to spend more time writing tests.
© 2015 McWest Corporation 8
Survey• 60 attendees (room nearly full)• Development languages
• Java (all), Groovy (all), scala (none), clojure (none), JavaScript(10), other
• Testing tools • Junit (all), TestNG(2), Spock (most), other
• OS (development)• Mac (1/4), Windows (2/3), Linux (handful)
• IDE• IntelliJ (1/2), STS (4), Bare eclipse (1), Sublime (1), emacs, nano,
vi, other• TDD (3)
© 2015 McWest Corporation 9
Spock TDD Case Study
© 2015 McWest Corporation 10
Calculating Calories from Proximates• Calories =
4 * carbs + 9 * fat + 4 * protein + 7 * alcohol
© 2015 McWest Corporation 11
Additional requirement: Missing proximates• Don’t calculate calories if we don’t have proximate values
© 2015 McWest Corporation 12
Problem• Calories aren’t calculating for most of our foods
New Requirement: If alcohol value is missing, assume it is zero
© 2015 McWest Corporation 13
New requirement: Missing ingredient values• If ingredients are missing one or more proximate values, flag the
calorie value as having missing ingredient values
© 2015 McWest Corporation 14
New requirement: Ingredient missing alcohol• If alcohol is missing in one of the ingredients, don’t flag the calorie
value as having missing ingredient values.
© 2015 McWest Corporation 15
Initial algorithm Final algorithm
Case Study Takeaway:Functionality starts simple, becomes complicated
© 2015 McWest Corporation 16
With specs…• Implementation can be
refactored, is maintainable, and is documented
Without specs…• Implementation
becomes unmaintainable (imagine first implementation patched to implement final implementation) and undocumented
Case Study Takeaway
© 2015 McWest Corporation 17
Case Study Takeaway: Reflections• Is the final where table too large? • If so, how would you break it into smaller tables? • Extra credit: if you break the test up, what new test(s) might you
introduce to show how all requirements relate to each other?
© 2015 McWest Corporation 18
Spock TDD Case Studyhttps://github.com/bwestrich/tdd-spock/blob/master/src/test/groovy/mcwest/casestudies/calories/README.md
© 2015 McWest Corporation 19
TDD Benefits and Costs• Benefits
• Immediate developer feedback• Improves design• Documents system• Allows safe refactoring
• Costs• Time to write tests• Time to run tests• Harder to refactor?
© 2015 McWest Corporation 20
Spock Tests as Assets
© 2015 McWest Corporation 21
What I’ll cover on Spock in next section• Spock best practices• Not an intro to Spock• Not a comprehensive review of all Spock’s features• Spock code examples most useful if you have a basic knowledge of
Spock or mocking/stubbing• For a Spock overview, see Spock references listed at
https://github.com/bwestrich/tdd-spock
© 2015 McWest Corporation 22
Spock Tests as Assets: Best practices, with code examples• Name methods well (NamingTestsSpec)• Use behavioral syntax (UseGivenNotSetupSpec)• Comments on blocks (optional) (UseGivenNotSetupSpec)• Emphasize typical cases (SpecifyClassUnderTestSpec)• Put expected values at end of tables (SpecifyClassUnderTestSpec)• Use double vertical bars to highlight results
(SpecifyClassUnderTestSpec)• Use comments and @Unroll in tables (SpecifyClassUnderTestSpec)• Avoid double trouble (StubsAndMocksSpec)• Fix broken tests (VaCalculateCaloriesFunctionalSpec)• Limit size of tables (SmallerWhereSpec)* class names (camel case capital letters)
© 2015 McWest Corporation 23
Spock Tests as Assets https://github.com/bwestrich/tdd-spock/blob/master/README.md
© 2015 McWest Corporation 24
Testing Effectively
© 2015 McWest Corporation 25
Testing effectively• Types of tests• Finding tests• Writing tests• Running tests• Testing before committing
© 2015 McWest Corporation 26
Types of (automated) testsType What it tests Spock support Comment
Functionalhow system works
from “user’s” perspective
Geb Most importantLowest coverage
Unit details mocks/stubs Fast, funHighest coverage
Integration how details work together
controller web tests*
Usage varies for different projects
Smoke deployments Geb Spot check
* https://github.com/bwestrich/tdd-spock/blob/master/README-MOCKMVC.md
© 2015 McWest Corporation 27
Spock uses same syntax for all test types
© 2015 McWest Corporation 28
Red Green Clean1. Write new or break existing test
2. Fix test
3. Clean (refacto
r)
© 2015 McWest Corporation 29
Don’t trust a test that hasn’t failed-- Kevin Beatty
© 2015 McWest Corporation 30
Using test types: Unit First1. Write/break unit test2. Fix unit test3. Clean test code and tested code4. Write/break integration test (optional)5. Fix integration test6. Clean test code and tested code7. Write/break functional test (optional)8. Fix functional test 9. Clean test code and tested code
© 2015 McWest Corporation 31
Using test types: Functional First1. Write/break functional test (optional)2. Write/break integration test (optional)3. Write/break unit test4. Fix unit test5. Clean test code and tested code6. Fix integration test7. Clean test code and tested code8. Fix functional test 9. Clean test code and tested code
© 2015 McWest Corporation 32
Order of Test Types for Different TasksTask Usual Approach NoteDefect fix FF Developer-reported
defects might use UFNew feature (tools and requirements well understood)
UF Business requested? FF
New feature (when learning technology or requirements)
Whatever approach works (even writing code before tests!)
Feature is not complete until tests pass and refactoring complete
Legend: FF = Functional First, UF = Unit First
© 2015 McWest Corporation 33
Write tests as soon as possible• The sooner you write tests, the better they can help guide your design
• OK: write code, then (before pushing) test code• Better: write tests while you write the tested code• Best: write tests before the tested code.
o Added benefit: verify the test fails before feature written / defect fixed (don’t trust a test that hasn’t failed)
© 2015 McWest Corporation 34
Different projects use different test types
Test type Run duration When runUnit < 1 minute Constantly while
coding, pre-pushIntegration 10 minutes Pre-pushFunctional None n/a
Project: Provide website content for nationwide electronics retailer, no front-end development done by our team.
© 2015 McWest Corporation 35
Different projects use different test types
Test type Run duration When runUnit < 1 minute Constantly while
coding, pre-pushIntegration 1 minute Occasionally while
coding, pre-pushFunctional 10 minutes Pre-push
Project: Departmental app, full-stack development.
© 2015 McWest Corporation 36
Reliable integration and functional tests• Don’t tolerate “false positives”
• Tests that fail for any reason other than defective software• Decrease value of your tests• “Fix broken windows”
• Tips on avoiding “false positives”• @Stepwise• Manage your test data• Extend Geb as needed
© 2015 McWest Corporation 37
Use @Stepwise to guarantee run method order
© 2015 McWest Corporation 38
Manage your test data• Script it!
• SQL, DBUnit, etc.• Periodically refresh all data in test environments • Reserve ranges for testing
• ID numbers (negative IDs? Large IDs?) • Code values• Other special “marking”
• Tests should not change shared data (allows concurrent test runs)
© 2015 McWest Corporation 39
Geb testing of asynchronous JavaScript• Using angular? Try ng-busy to manage asynchronous processing
• Use ng-busy to display a ‘Processing’ message to users while waiting for any http server requests, have tests wait when label is displayed
Page object method
Example code in test
© 2015 McWest Corporation 40
Using test types: Takeaway• All types of tests are an integral part of development• Use the correct test type for the job at hand• Use test types that fit your project• Write tests as soon as possible• Prevent false-positives
• And, of course….. ;-) • Run ALL test types before pushing changes
© 2015 McWest Corporation 41
Keyboard shortcuts• Learn and use them! (pairing?)• OS and IDE specific
• OS: Mac, Linux, Windows• IDE: IntelliJ, Eclipse, nano, emacs, vi, …….• This presentation uses Mac (OSX) and IntelliJ 14.1.4
© 2015 McWest Corporation 42
Finding Tests• Test location
• As close to Class Under Test as possible• Same project, package, name prefix (MyClass and MyClassSpec)• Different source folder
• Keyboard shortcuts (DEMO)• Toggle between class and test: Cmd-Shift-T• Find by name: Cmd-Shift-O
o (type caps to exploit camel case, e.g. MCS finds MyClassSpec)
© 2015 McWest Corporation 43
Writing Tests• Where table keyboard shortcuts (DEMO)
• Column editingo Createo Updateo Delete
• Column formatting: Cmd-Alt-L
© 2015 McWest Corporation 44
Running Tests (IDE)• Keyboard shortcuts (DEMO)
• Ctrl-Shift-R: Run highlighted test• Ctrl-R: Run previously run test
© 2015 McWest Corporation 45
Running Tests (command line)• Create team aliases for common operations for your team’s
languages / frameworks / build systems• Operations
o refresh dependencies, clean, test, run• Languages / frameworks: build systems
o JavaScript/Angular: grunt, gulpo Java/Groovy/Spring Boot: maven, gradle
© 2015 McWest Corporation 46
Running tests command line (DEMO)
© 2015 McWest Corporation 47
Running Tests (command line) (cont.)
• Team aliases• Add to source control • Add directory to execution path• Provide easy ways for team to update (“ea”, “listaliases”)
• Basic example: https://github.com/mcwest/team-aliases• Supports:
© 2015 McWest Corporation 48
Test Before Pushing• The right way: Run all tests (of all types) before pushing (to source
control)• Why it’s hard to do:
• Commands to run tests are arcane, inconsistent, error prone• Tests take long time to run• Tests fail after running long time (waste of time!)• Results hard to find/interpret (just say ‘ok’ or ‘not’)• While waiting, you can’t do ANYTHING else
• How to make the right way easy?
© 2015 McWest Corporation 49
Asynchronous pre-push testing (via script)• Call script something short: e.g. “go”• What script does
• Cleans and builds all components in separate workspace• Runs ALL unit/integration/functional tests and code style checkers• Fails fast (slow tests run last)• Runs in background
o Spawns separate instance of components with dedicated resources (workspace, ports, data, log files, …)
o Audio notification of results (have some fun here!)• Manage same as a team alias (in source control, on execution path)
© 2015 McWest Corporation 50
Before svn commit1. ‘go’, then if errors, fix and refactor 2. ‘svn update’3. if changes, go back to step 1, otherwise ‘svn commit’
© 2015 McWest Corporation 51
Before git push1. ‘go’, then if errors, fix and refactor 2. ‘git commit’3. ‘git smart-pull’ (alias ‘gsp’)4. if changes, go back to step 1, otherwise ‘git push’
• Notes: • Step #2 makes git merges easier to manage by not mixing local changes
and remote changes into same commit• Step #3 uses the excellent git smart-pull add-on, see
https://github.com/mcwest/team-aliases for more info
© 2015 McWest Corporation 52
Asynchronous pre-push testing (other methods)• Team City (JetBrains): not out of the box, need to configure post-
commit hook• Other tools?• Anyone have solutions to share to this?
© 2015 McWest Corporation 53
Testing effectively (review)• Types of tests• Finding tests• Writing tests• Running tests• Testing before committing
© 2015 McWest Corporation 54
TDD in Teams• Pair Programming• Pull Requests• Continuous Integration• Continuous Deployment
© 2015 McWest Corporation 55
Pair Programming• Wonderful way to learn, teach, enjoy TDD/Spock• Very productive• Roles
• Driver (shows new ways to find/write/run/commit tests)• Observer (watches for typos, testing the right thing, next test
type)• Keep both members switching roles
• TDD ping pong: ping pong ping pong ping pong• Other ideas?
• Cautions• Team must want to pair (pre-interview question)• Workspace must be conducive to pairing
© 2015 McWest Corporation 56
Pair Programming Workspace
© 2015 McWest Corporation 57
Pull Requests (PR)• Great compliment to / replacement for pairing
• Does not require workspace re-config• Works with remote teams (but can pair over skype/hangouts/…)• More conducive to some developers’ workstyles than pairing
• TDD and PRs• Submitter must include tests in the PR• Reviewer should run tests in background (using ‘go’) while
reviewing• Cautions
• Requires understanding of source code branching• Commands to create PR’s not trivial
o Set up command line aliases to streamline
© 2015 McWest Corporation 58
Continuous Integration• Trigger build immediately on push (commit hooks preferred over
polling)• Notify team of broken builds
• Emails• Texts• IM/Slack?
• Make broken builds visible• Radiator (Jenkins plugin)
© 2015 McWest Corporation 59
Continuous Deployment• Impossible without automated tests• TDD a great way (the only way) to build automated tests that verify a
system at all levels
© 2015 McWest Corporation 60
Test MantrasMantra -- “a statement or slogan repeated frequently”
• Test the right thing• APIs not internals• Don’t trust a test that hasn’t failed• The right way easy• Tests are assets not afterthoughts
© 2015 McWest Corporation 61
Spock: Specification at all levels
© 2015 McWest Corporation 62
From the smallest unit…
© 2015 McWest Corporation 63
… to detailed interactions …
© 2015 McWest Corporation 64
… to higher level interactions …
© 2015 McWest Corporation 65
… to the user’s view of the system.
© 2015 McWest Corporation 66
The needs of the many outweigh the needs of the few.
© 2015 McWest Corporation 67
ConclusionUsing the techniques and approaches we’ve discussed, automated developer-written tests become less something we do as an afterthought (if at all), and more an asset we demand on our future projects.
© 2015 McWest Corporation 68
Resources• Spock TDD: https://github.com/bwestrich/tdd-spock• TDD cribsheet (JUnit oriented):
https://bitbucket.org/bwestrich/java-tdd• Command line aliases: https://github.com/mcwest/team-aliases
© 2015 McWest Corporation 69
Spock ‘seed art’ credit
© 2015 McWest Corporation 70
Minneapolis ‘seed art’ credit
© 2015 McWest Corporation 71
Spock TDD
Tests as Assets not Afterthoughts
by Brian Westrich, McWest [email protected]