My talk delivered on 10th of April 2014 in Bristol at ACCU Conference.
This is the combination of a few talks I delivered over 2012 and 2013 with some latest updates.
This is an experience report based on the work of many developers from Atlassian and Spartez working for years on Atlassian JIRA.
If you have (or going to have) thousands of automated tests and you are interested how it may impact you, this presentation is for you.
2. About me
• Coding since 6yo
• Former C++ developer (’90s, early ’00s)
• Agile Practices (inc.TDD) since 2003
• Dev Nerd,Tech Leader, Agile Coach,
Speaker, PHB
• 6.5 years with Atlassian (JIRA Dev Manager)
• Spartez Co-founder & CEO
25. You commit at 3 PM
You get “Unit Test Green” email at 4PM
You get flood of “Red Test X” emails at 4 - 9PM
Your colleagues on the
other side of the globe
You happily go home
You
26. “We probably spend more
time dealing with the JIRA
test codebase than the
production codebase”
30. Catching up with UI
changes
Page Objects Pattern
Problem:
Solution:
31. Page Objects Pattern
• Page Objects model UI elements (pages,
components, dialogs, areas) your tests
interact with
• Page Objects shield tests from changing
internal structure of the page
• Page Objects generally do not make
assertions about data. The can assert
the state.
• Designed for chaining
32. Page Objects Example
public class AddUserPage extends AbstractJiraPage!
{!
!
private static final String URI = !
"/secure/admin/user/AddUser!default.jspa";!
!
@ElementBy(name = "username")!
private PageElement username;!
!
@ElementBy(name = "password")!
private PageElement password;!
!
@ElementBy(name = "confirm")!
private PageElement passwordConfirmation;!
!
@ElementBy(name = "fullname")!
private PageElement fullName;!
!
@ElementBy(name = "email")!
private PageElement email;!
!
@ElementBy(name = "sendemail")!
private PageElement sendEmail;!
!
@ElementBy(id = "user-create-submit")!
private PageElement submit;!
!
@ElementBy (id = "user-create-cancel")!
private PageElement cancelButton;!
!
@Override!
public String getUrl()!
{!
return URI;!
}!
...
@Override!
public TimedCondition isAt()!
{!
return and(username.timed().isPresent(), !
password.timed().isPresent(), fullName.timed().isPresent());!
}!
!
public AddUserPage addUser(final String username, !
final String password, final String fullName, final String
email, final boolean receiveEmail)!
{!
this.username.type(username);!
this.password.type(password);!
this.passwordConfirmation.type(password);!
this.fullName.type(fullName);!
this.email.type(email);!
if(receiveEmail) {!
this.sendEmail.select();!
}!
return this;!
}!
!
public ViewUserPage createUser()!
{!
return createUser(ViewUserPage.class);!
}!
!
!
public <T extends Page> T createUser(Class<T> nextPage,
Object...args)!
{!
submit.click();!
return pageBinder.bind(nextPage, args);!
}!
33. Using Page Objects
@Test!
public void testServerError()!
{!
jira.gotoLoginPage().loginAsSysAdmin(AddUserPage.class)!
.addUser("username", "mypassword", "My Name",!
"sample@email.com", false)!
.createUser();!
// assertions here!
}!
50. Build Tiers and Policy
Tier A1 - green soon after all commits
Tier A2 - green at the end of the day
Tier A3 - green at the end of the iteration
unit tests and functional* tests
WebDriver and bundled plugins tests
supported platforms tests, compatibility tests
52. Training
• assertThat over assertTrue/False and
assertEquals
• avoiding races - Atlassian Selenium with its
TimedElement
• Favouring unit tests over functional tests
• Promoting Page Objects
• Brownbags, blog posts, code reviews
59. Ditching - benefits
• Freed build agents - better system throughput
• Boosted morale
• Gazillion of developer hours saved
• Money saved on infrastructure
60. Ditching - due diligence
• conducting the audit - analysis of the
coverage we lost
• determining which tests needs to rewritten
(e.g. security related)
• rewriting the tests (good job for new hires
+ a senior mentor)
61. Flaky Browser-based Tests
Races between test code and asynchronous page logic
Playing with "loading" CSS class does not really help
62. Races Removal with Tracing
// in the browser:!
function mySearchClickHandler() {!
doSomeXhr().always(function() {!
// This executes when the XHR has completed (either success or failure)!
JIRA.trace("search.completed");"
});!
}!
// In production code JIRA.trace is a no-op
// in my page object:!
@Inject!
TraceContext traceContext;!
!
public SearchResults doASearch() {!
Tracer snapshot = traceContext.checkpoint();!
getSearchButton().click(); // causes mySearchClickHandler to be invoked!
// This waits until the "search.completed"
// event has been emitted, *after* previous snapshot !
traceContext.waitFor(snapshot, "search.completed"); !
return pageBinder.bind(SearchResults.class);!
}!
74. • Proximity of SCM repo
• shallow git clones are not so fast and lightweight +
generating extra git server CPU load
• git clone per agent/plan + git pull + git clone per build
(hard links!)
• Stash was thankful (queue)
SCM Update - Checkout time
2 min → 5 seconds
77. Compilation
• Restructuring multi-pom maven project
and dependencies
• Maven 3 parallel compilation FTW
-T 1.5C
*optimal factor thanks to scientific trial and error research
7 min → 1 min
78. Unit Test Execution
• Splitting unit tests into 2 buckets: good and
legacy (much longer)
• Maven 3 parallel test execution (-T 1.5C)
7 min → 5 min
3000 poor tests
(5min)
11000 good tests
(1.5min)
79. Functional Tests
• Selenium 1 removal did help
• Faster reset/restore (avoid unnecessary
stuff, intercepting SQL operations for debug
purposes - building stacktraces is costly)
• Restoring via Backdoor REST API
• Using REST API for common setup/
teardown operations
81. Publishing Results
• Server log allocation per test → using now
Backdoor REST API (was Selenium)
• Bamboo DB performance degradation for
rich build history - to be addressed
1 min → 40 s
82. Unexpected Problem
• Stability Issues with our CI server
• The bottleneck changed from I/O to CPU
• Too many agents per physical machine
84. Improvements Summary
Tests Before After Improvement %
Unit tests 29 min 17 min 41%
Functional tests 56 min 34 min 39%
WebDriver tests 39 min 21 min 46%
Overall 124 min 72 min 42%
* Additional ca. 5% improvement expected once new git clone
strategy is consistently rolled-out everywhere
89. Inevitable Split - Fears
• Organizational concerns - understanding,
managing, integrating, releasing
• Mindset change - if something worked for
10+ years why to change it?
• Trust - does this library still work?
• We damned ourselves with big buckets for
all tests - where do they belong to?
90. Splitting code base
• Step 0 - JIRA Importers Plugin (3.5 years ago)
• Step 1- New IssueView and Navigator
• Step 2 - now everything else follows JIRA 6.0
91. We are still escaping hell.
Hell sucks in your soul.
92. Conclusions
• Visibility and problem awareness help
• Maintaing huge testbed is difficult and costly
• Measure the problem - to baseline
• No prejudice - no sacred cows
• Automated tests are not one-off investment,
it's a continuous journey
• Performance is a damn important feature
94. XP vs Sad Reality
CostofChange
Time
Waterfall
XP - ideal
Sad Reality
95. Interested in such stuff?
http://www.spartez.com/careers
We are hiring in Gdańsk
96. • Turtle - by Jonathan Zander, CC-BY-SA-3.0
• Loading - by MatthewJ13, CC-SA-3.0
• Magic Potion - by Koolmann1, CC-BY-SA-2.0
• Merlin Tool - by By L. Mahin, CC-BY-SA-3.0
• Choose Pills - by *rockysprings, CC-BY-SA-3.0
• Flashing Red Light - by Chris Phan, CC BY 2.0
• Frustration - http://www.flickr.com/photos/striatic
• Broken window - http://www.flickr.com/photos/leeadlaf/
Images - Credits