testability for developers – fighting a mess by making it testable
DESCRIPTION
My talk from XP Days Ukraine 2012.TRANSCRIPT
Testability for developers
Fighting a mess by making it testable
XP Days Ukraine 2012Alexander Tarnowski
Additional note: This presentation has been slightly adjusted after the conference. Some images have been removed and some notes have been added to provide context.
Ongoing project
http://leanpub.com/developer_testing
alexander_tar
blog.crisp.se/author/alexandertarnowskiBlog
www
www.techbookreader.com
My system’s dependencies are like spaghetti
It’s a ritual to deploy my systemMy system is ruled by a database
My system doesn’t have a business layerMy system has few and poor unit testsMy system’s end-to-end tests don’t work
Frontend
”Enterprise-wide” component Backend
EWCcore
EWCshared
Backendcore
Backend
shared
Frontend
Enterprise message bus libraryJoker: flickr: GoShows
WS developer pack from 2004
LegendEWC = Enterprise-wide componment = Depends on = Packaged into
Alternative message queue implementation
A number of data sources
Message bus library
Application’s config files
Parts of the application
?
flickr: Andrew Coulter Enright
One Database to rule them all, One Database to find them,
One Database to bring them all and in the darkness bind them
flickr: rfzappala
Additional note: A lengthy manual deployment script that’s not up-to-date has a striking resemblance to hieroglyphs.
DatabaseGood idea Bad idea
Additional note: Some frameworks try really hard to provide persistence as close to the view as possible. When is that a good idea?
Είχαν τεσσαρών μεταγλωτίσει ας σαν, αλφα εκτελείται δεν τι. Από θα χρόνου χαμηλός ποσοστό. Γειτονιάς εργαζόμενων να πεςεπενδυτής το. Χάος προσεκτικά δε στη. Όρο πάρα ιδιαίτερα αν, όσο το πετούν γνωρίζει.Το όσο γραφικά δημιουργίες χαρακτηριστικό, όλα μη έργων περίπου. Διακοπή οέλεγχος χαρακτηριστικών να όχι, μη Ήδη έτσι Thread.sleep(3000);
χρόνου θα. Στο με όταν λοιπόν σημαντικός, έρθει σχεδιαστής ήδη τι. Ας την γειτονιάς αγοράζοντας. Ας πετούν αποτελέσει θα μπουν προσλάμβανες, πιο ως στην προσπαθούν.Thread.sleep(3000);Πω δουλέψει προσεκτικά χαρακτηριστικών σου, έστελνε φακέλους ανακλύψεις τι νέα. Ατόμου αποφάσισε που τι, προσλάμβανες των, ποσοστό επιτίθενται το ναι. Πω ερωτήσεις χρειάζονται λες, βήμα πάρεις κρατάει να κλπ. Την ξεχειλίζει. Την πετάνε χαμηλός χαρακτηριστικών να, δε κρατήσουν προβληματική μην. Τη κύκλο κανείς απίστευτα ώρα, αλγόριθμου προβλήματα αντιλήφθηκαν.Υόρκη καρέκλα λιγότερο να ότι, τότε μπουν κρατάει πιο οι. Τι σου γραφικά αρπάζεις δουλεύουν. Ώς βαθμό δημιουργίες, μια μα θέματα
διοικητικό, δε πελάτες δυστυχώς συγχρόνως σας. Κι τους δίνοντας λες. Νέες εξαρτάται οι όχι, ώς ξέχασε προϊόντα ότι.Thread.sleep(1000);Με μάλλον κακόκεφους χρησιμοποιούνταν που, μετρήσεις εργοστασίου παρατηρούμενη τη λες. Λοιπόν ναί να. Αν ήδη νέων εκτός, Thread.sleep(2000);
σας άρθρων χρήματα χρησιμοποιήσει μη. Εδώ άμεση ατόμου αναγκάζονται μα, μέσης τελικών σφαλμάτων εταιρείες τα. Thread.sleep(3000);Δούλευε μηχανής ροή κι, ώς τέτοιο διακοπή αναζήτησης τον, τις ορίστε ατόμου εργαζόμενων ώς. Όχι λοιπόν κρατάει θα. Μάθε όχι
flickr: bunky’s pickle
Additional note: Long record/playback tests with incorrect handling of asynchronicity tend to look like Greek after a while.
Database
One database
Dependency spaghetti
Few and poor unit tests
No business layer
Manual deployment
Unknown app server configuration
?Record/playback
(with timing issues)
Where do we start
What Why
New code unit-tested We’re in a hole and we don’t want to dig deeper
Create a business layer Quality in the long run
Automated end-to-end tests for happy paths
• Initiate change • ”Quick” wins
@Test public void aUserCanLogIn() {
application.login(”testuser”, ”secret”);}
Additional note: Yes, this test has no assertion. Fundamental checks, such as verifying navigation, are built into the test infrastructure.
Login test runs
Application deployed to a
server with known config
Deployment automated
Creating new databases
with classified data is easy
Start
GOAL
Additional note: Sequence of steps to reach a state where a fundamental login test (smoke test) could be executed.
Fixing the dependency mess, the unit tests, and adding a business layer became an ongoing activity (= outside the scope of this talk).
flickr: Klearchos Kapoutsis
Work the system
See where it crashes
Add the missing object
Classify data
Document
Add data to object
Drop all objects
Import all objects
181Additional note: At the time of the conference, the system had been automatically deployed 181 times. In ½ year, that’s roughly once a day. Given that manual deployment took between 5-60 minutes, the time saved was 2 weeks.
Test framework @Test
Flow/business application.login(”testuser”, ”secret”);
Page/dialog loginPage.enterUserName(”testuser”);loginPage.enterPassword(”secret”);loginPage.clickLoginButton();
Internals webDriver.findElementBy(id(”text_user”)) .setText(”testuser”);webDriver.findElementBy(id(”text_password”)) .setText(”secret”);
Our take aways and advice – Big picture
• Don’t be overwhelmed• Black boxes in your environment make
you feel uneasy and waste time• Achieving testability proved to
be a good guide• After a while, the approach
became second nature
Take aways – Details
• Using simple tools helped us save time• End-to-end tests without controlling the
database shouldn’t and didn’t work• Record/playback didn’t work this time either• Nobody asked about ”acceptance tests
readable by the stakeholders”
However...
2012-10-22 16:16:31,528 ERROR [http-127.0.0.1-8989-2] (SynchronizationRegistry.java:46) - Exception processing transaction Synchronization after completionjava.lang.NullPointerExceptionat com.organization.system.TreeObject.isEquipment(TreeObject.java:34)
Additional note: It doesn’t matter if you can get your test infrastructure right. Quality cannot be tested in. Spaghetti dependencies, poor unit test coverage and lack of business layer still were a problem.