SlideShare a Scribd company logo
1 of 103
Download to read offline
Developer Tests 
Things to Know 
Vaidas Pilkauskas 2014 
Vilnius JUG 
vaidas.pilkauskas@gmail.com
me 
My hobbies 
● developer at Wix.com 
● main language - Scala 
● main professional interest - developer communities 
If there is time left after my hobbies 
● mountain bicycle rider, snowboarder 
● consumer of rock music, contemporary art, etc
me - how to contact me 
connect with me on LinkedIn http://lt.linkedin. 
com/pub/vaidas-pilkauskas/8/77/863/ 
add me on G+ https://www.google.com/+VaidasPilkauskas 
follow on Twitter @liucijus
“We couldn’t understand why people without technical 
knowledge had to tell programmers “what” to do and, 
furthermore, they had to supervise “how” 
programmers did it.” 
Cristian Rennella 
http://qz.com/260846/why-our-startup-has-no-bosses-no-office-and-a-four-day-work-week/
What this talk is about 
● Things we argue about during code reviews 
● Things that took me time to understand and 
prove that they are actually good way to go 
● Small things we have no time to discuss 
during big talks
“Legacy Code is code without 
Tests” 
Michael Feathers 
Working Effectively with Legacy Code
So what is test? 
It is system’s exercise under predefined 
conditions and then verification of an 
expected outcome.
Thing #1 
Test structure
Test phases 
Setup 
Exercise 
Verify 
Teardown
Test phases in code 
Server server = new NotesServer(); // setup 
Note note = new Note("test note"); // setup 
Status status = server.add(note); // exercise 
assertEquals(SUCCESS, status); // verify 
server.shutdown(); // teardown
Start everything in one method 
@Test 
public void serverShouldAddNoteSuccessfully() { 
Server server = new NotesServer(); // setup 
Note note = new Note("test note"); // setup 
Status status = server.add(note); // exercise 
assertEquals(SUCCESS, status); // verify 
server.shutdown(); // teardown 
}
Refactor to lifecycle methods 
@Before public void before() { 
server = new NotesServer(); // setup 
note = new Note("test note"); // setup 
} 
@Test public void serverShouldAddNoteSuccessfully() { 
Status status = server.add(note); // exercise 
assertEquals(SUCCESS, status); // verify 
} 
@After public void after() { 
server.shutdown(); // teardown 
}
DON’Ts - #1 
Do not start from setup/teardown
DON’Ts - #2 
Do not mix setup code from different 
tests - shared code must be relevant to 
the tests that use it
DON’Ts - #3 
Setup and teardown are there to solve 
DRY problem and to help structure your 
test code
How many colors are there in the 
picture? 
Source: Josef Albers Interaction of Color
Context matters! 
Source: Josef Albers Interaction of Color
Typical setup inside @Before 
@Before public void before() { 
server = new NotesServer(); // setup 
note = new Note("test note"); // setup 
} 
@Test public void serverShouldAddNoteSuccessfully() { 
Status status = server.add(note); // exercise 
assertEquals(SUCCESS, status); // verify 
} 
@After public void after() { server.shutdown(); // teardown }
Setup pollution - #1 
● Every line in setup must be relevant to all tests.
Setup pollution - #2 
● It is tempting to add additional setup tuning just to 
fix/enhance one test.
Setup pollution - #3 
● Rich setup makes tests slow!
Setup pollution - #4 
● Setup is to bootstrap your SUT.
Setup pollution - #5 
● Setup hides details! Do not hide test preconditions.
Setting up “job” inside test method 
@Before public void before() { 
server = new NotesServer(); // setup 
} 
@Test public void serverShouldAddNoteSuccessfully() { 
note = new Note("test note"); // setup 
Status status = server.add(note); // exercise 
assertEquals(SUCCESS, status); // verify 
}
But then be more specific 
@Test 
public void serverShouldAddSingleLineNoteSuccesfully() { 
// * set up which is actual for the current method 
// * use scope specific name 
Note singleLineNote = new Note("test note"); // setup 
Status status = server.add(singleLineNote); // exercise 
assertEquals(SUCCESS, status); // verify 
}
Give good names to setup methods 
@Before public void createNotesServer() { 
server = new NotesServer(); 
}
Summary of test code organization 
● DRY principle. 
● Readability. BDD vs. DRY 
● Consistency. Maintain the same style across 
your codebase. 
● Complexity. It may dictate the way you go.
Refactoring 
Refactoring is about improving the design of 
existing code. It is the process of changing a 
software system in such a way that it does not 
alter the external behavior of the code, yet 
improves its internal structure. 
Martin Fowler 
Refactoring: Improving the Design of Existing Code
Thing #2 
What do we test?
Test behaviour not methods 
● Think of a contract
Test behaviour not methods 
● Think of a contract 
● And responsibilities
Test behaviour not methods 
● Think of a contract 
● And responsibilities 
● Specify requirements as tests
Test behaviour not methods 
● Think of a contract 
● And responsibilities 
● Specify requirements as tests 
● Happens naturally when done in test-first 
approach
Thing #3 
Matchers
Matchers 
● Enhance readability 
● Asserts on the right level of abstraction 
● Encapsulate testing logic 
● Reusable 
● Detailed match error messages (do not 
leave them out in your custom matchers!)
Matchers 
● Enhance readability 
● Asserts on the right level of abstraction 
● Encapsulate testing logic 
● Reusable 
● Detailed match error messages (do not 
leave them out in your custom matchers!)
Matcher libraries 
● Hamcrest - standard matcher lib for JUnit 
● AssertJ - fluent assertions (IDE friendly) 
● Provides common matchers 
● You can write your own custom matchers
Hamcrest 
assertThat(frodo.getName(), equalTo("Frodo")); 
assertThat(frodo.getName(), is(equalTo("Frodo"))); 
assertThat(frodo.getName(), is("Frodo"));
AssertJ 
assertThat(frodo.getName()).isEqualTo("Frodo"); 
assertThat(frodo).isNotEqualTo(sauron).isIn(fellowshipOfTheRing); 
assertThat(sauron).isNotIn(fellowshipOfTheRing);
Thing #4 
Custom matchers
Custom matchers 
Are matchers that we write specifically for our 
projects.
Custom matchers 
● Help communicate test intention 
● Abstract assertion logic in case standard 
matchers are not enough 
● Are reusable and save time in large projects 
● You may have a custom message to be 
more specific about test failure
Custom matchers 
● Help communicate test intention 
● Abstract assertion logic in case standard 
matchers are not enough 
● Are reusable and save time in large projects 
● You may have a custom message to be 
more specific about test failure
Custom matchers 
@Test 
public void shouldHaveIsbnGenerated() { 
Book book = new Book(1l, "5555", "A book"); 
assertThat(book, hasIsbn("1234")); 
}
Thing #5 
Failing a test
fail() 
In some cases (e.g. testing exceptions) you 
may want to force test to fail if some expected 
situation does not happen
fail() 
try { 
// do stuff... 
fail("Exception not thrown"); 
} catch(Exception e){ 
assertTrue(e.hasSomeFlag()); 
}
fail() 
● Fundamentally not bad, but better use 
matchers for expected failure 
● Matchers help to clarify test intention 
● Don’t forget - expected behaviour is an 
opposite of a failing test
Thing #6 
Anti-pattern: The Ugly Mirror
Anti-pattern: The Ugly Mirror 
@Test 
public void personToStringShouldIncludeNameAndSurname() { 
Person person = new Person("Vilkas", "Pilkas"); 
String expected = 
"Person[" + person.getName() + " " + person.getSurname() + "]" 
assertEquals(expected, person.toString()); 
}
Anti-pattern: The Ugly Mirror 
@Test 
public void personToStringShouldIncludeNameAndSurname() { 
Person person = new Person("Vilkas", "Pilkas"); 
String expected = 
"Person[" + person.getName() + " " + person.getSurname() + "]" 
assertEquals(expected, person.toString()); 
}
Anti-pattern: The Ugly Mirror 
@Test 
public void personToStringShouldIncludeNameAndSurname() { 
Person person = new Person("Vilkas", "Pilkas"); 
assertEquals("Person[Vilkas Pilkas]", person.toString()); 
}
Thing #7 
How to turn off the test?
Why would you want to turn off the 
test?
Why would you want to turn off the 
test? 
Well, because it fails… :)
Ignoring tests 
● Always use ignore/pending API from your 
test library (JUnit @Ignore)
Ignoring tests 
● Always use ignore/pending API from your 
test library (JUnit @Ignore) 
● Do not comment out or false assert your test
Ignoring tests 
● Always use ignore/pending API from your 
test library (JUnit @Ignore) 
● Do not comment out or false assert your test 
● If you do not need a test - delete it
Thing #8 
What to do with exceptions?
Exceptions 
● If you can, use matchers instead of 
○ @Test(expected=?) 
○ try-catch approach
JUnit expected exception 
@Test(expected=IndexOutOfBoundsException.class) 
public void shouldThrowIndexOutOfBoundsException() { 
ArrayList emptyList = new ArrayList(); 
Object o = emptyList.get(0); 
} 
//matcher in Specs2 (Scala) 
server.process(None) must throwA[NothingToProccess]
try and catch 
public void shouldThrowIndexOutOfBoundsException() { 
ArrayList emptyList = new ArrayList(); 
try { 
Object o = emptyList.get(0); 
fail("Should throw IndexOutOfBoundsException"); 
} catch(IndexOutOfBoundsException e)){ 
//consider asserting message! 
} 
}
Exceptions 
● catch-exception lib
catch-exception lib 
List myList = new ArrayList(); 
catchException(myList).get(1); 
assertThat(caughtException(), 
allOf( 
is(IndexOutOfBoundsException.class), 
hasMessage("Index: 1, Size: 0"), 
hasNoCause() 
) 
);
Exceptions 
● What about ExpectedException Rule? 
○ My personal opinion - not that intuitive 
○ breaks arrange/act/assert flow
ExpectedException rule 
@Rule public ExpectedException exception = ExpectedException.none(); 
@Test 
public void testExpectedException() { 
exception.expect(IllegalArgumentException.class); 
exception.expectMessage(containsString('Invalid age')); 
new Person('Vilkas', -1); 
} 
//Person constructor 
public Person(String name, int age) { 
if (age <= 0) throw new IllegalArgumentException('Invalid age:' + age); 
// ... 
}
Thing #9 
Testing with time
Problem 
public class MyService { 
... 
public void process(LocalDate date) { 
if (date.isBefore(LocalDate.now()) { 
... 
} 
} 
}
Testing with Time 
● Design your system where time is a 
collaborator 
● Inject test specific time provider in your test 
○ constant time 
○ slow time 
○ boundary cases time
Control time with Clock 
public class MyService { 
private Clock clock; // dependency inject 
... 
public void process(LocalDate date) { 
if (date.isBefore(LocalDate.now(clock)) { 
... 
} 
} 
}
Thing #10 
Collections
Collections - multiple properties to 
assert 
● Is null? 
● Size 
● Order 
● Content
Collections 
● Most of the time you want to assert on collection content
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching 
● Avoid incomplete assertions
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching 
● Avoid incomplete assertions 
● Do not sort just because it is easier to assert!
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching 
● Avoid incomplete assertions 
● Do not sort just because it is easier to assert! 
● Multiple assertions are worse than single content 
assertion
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching 
● Avoid incomplete assertions 
● Do not sort just because it is easier to assert! 
● Multiple assertions are worse than single content 
assertion 
● Unless you want to say something important in your test!
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching 
● Avoid incomplete assertions 
● Do not sort just because it is easier to assert! 
● Multiple assertions are worse than single content 
assertion 
● Unless you want to say something important in your test! 
● Use matchers!
Collections 
● Most of the time you want to assert on collection content 
● Prefer exact content matching 
● Avoid incomplete assertions 
● Do not sort just because it is easier to assert! 
● Multiple assertions are worse than single content 
assertion 
● Unless you want to say something important in your test! 
● Use matchers!
Thing #11 
Random values
Random values in tests 
● Most of the time you do not want it
Random values in tests 
● Most of the time you do not want it 
● Unless you depend on randomness a lot (eg. 
password generation*) 
*Thanks to Aleksandar Tomovski for a good example
Random values in tests 
● Most of the time you do not want it 
● Unless you depend on randomness a lot 
● Use property based testing (which is also 
hard)
Random values in tests 
● Most of the time you do not want it 
● Unless you depend on randomness a lot 
● Use property based testing (which is also 
hard) 
● Do not make dummy values random
What if we still need random cases?
Generate Multiple Test Cases 
● Quality over quantity
Generate Multiple Test Cases 
● Quality over quantity 
● Think of boundary cases, that you may want 
to detect with random test
Generate Multiple Test Cases 
● Quality over quantity 
● Think of boundary cases, that you may want 
to detect with random test 
● Use parameterized tests
Generate Multiple Test Cases 
● Quality over quantity 
● Think of boundary cases, that you may want 
to detect with random test 
● Use parameterized tests 
● Random is hard to repeat
Generate Multiple Test Cases 
● Quality over quantity 
● Think of boundary cases, that you may want 
to detect with random test 
● Use parameterized tests 
● Random is hard to repeat 
● Flickering tests
Thing #12 
How many assertions per test?
How many assertions per test? 
● Unit test - one assertion per test. Must be 
clear and readable 
● Proper test should fail for exactly one reason 
● End to end - best case one assertion per 
test, but more are allowed 
● Consider custom matchers
How many assertions per test? 
● Unit test - one assertion per test. Must be 
clear and readable 
● Proper test should fail for exactly one 
reason 
● End to end - best case one assertion per 
test, but more are allowed 
● Consider custom matchers
Thing #13 
Decoupling in End-to-end tests
What can be better in this test 
[pseudocode] 
@Test shouldRetrieveUserByLogin() { 
String userJson = "{"username": "vaidas"}"; 
HttpRequest post = new Post("https://localhost:8080/users", userJson); 
HttpResponse postResp = HttpClient().execute(post); 
assertThat(postResp.status, is(200)); 
HttpRequest get = new Get("https://localhost:8080/users/vaidas"); 
HttpResponse getResp = HttpClient().execute(get); 
User user = mapper.readValue(getResp, User.class); 
assertThat(username, is("vaidas")); 
}
Decoupling from low level details 
[pseudocode] 
@Test shouldRetrieveUserByUsername() { 
CreateUserResponse createResp = aCreateUserRequest().withUsername("vaidas").execute(); 
assertThat(createResp, hasStatus(OK)); 
GetUserResponse getResp = aGetUserRequest().withUsername("vaidas").execute(); 
assertThat(getResp, allOf(hasStatus(OK), hasUsername("vaidas"))); 
}
Thoughts on end-to-end testing 
● What is real e2e? REST vs. UI 
● Testing by using system itself 
● Vs. using low level DB driver to verify data 
persistence
Thing #14 
Comments
Comments in Test code 
● Fundamentally good option to explain 
complicated parts, but: 
● better use good method naming 
● custom matcher 
● do less, so that intention is clear 
● comments are not so bad in isolated well 
named methods
Summary 
● Context matters 
● Tests are controversial topic 
● And very opinionated
Thanks! 
Q & A

More Related Content

What's hot

2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good TestsTomek Kaczanowski
 
Automated testing in Python and beyond
Automated testing in Python and beyondAutomated testing in Python and beyond
Automated testing in Python and beyonddn
 
GeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsGeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsTomek Kaczanowski
 
iOS Unit Testing
iOS Unit TestingiOS Unit Testing
iOS Unit Testingsgleadow
 
Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsTomek Kaczanowski
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testingpleeps
 
PgTAP Best Practices
PgTAP Best PracticesPgTAP Best Practices
PgTAP Best PracticesDavid Wheeler
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Howsatesgoral
 
Test driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesTest driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesNarendra Pathai
 
TDD in Python With Pytest
TDD in Python With PytestTDD in Python With Pytest
TDD in Python With PytestEddy Reyes
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummiesHarry Potter
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit TestingMike Lively
 
xUnit Style Database Testing
xUnit Style Database TestingxUnit Style Database Testing
xUnit Style Database TestingChris Oldwood
 

What's hot (19)

2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests
 
Automated testing in Python and beyond
Automated testing in Python and beyondAutomated testing in Python and beyond
Automated testing in Python and beyond
 
GeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsGeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good Tests
 
iOS Unit Testing
iOS Unit TestingiOS Unit Testing
iOS Unit Testing
 
Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good Tests
 
Refactoring
RefactoringRefactoring
Refactoring
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
ES3-2020-05 Testing
ES3-2020-05 TestingES3-2020-05 Testing
ES3-2020-05 Testing
 
PgTAP Best Practices
PgTAP Best PracticesPgTAP Best Practices
PgTAP Best Practices
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
 
Cursus phpunit
Cursus phpunitCursus phpunit
Cursus phpunit
 
Test driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practicesTest driven development - JUnit basics and best practices
Test driven development - JUnit basics and best practices
 
TDD in Python With Pytest
TDD in Python With PytestTDD in Python With Pytest
TDD in Python With Pytest
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
 
Unit Testing in iOS
Unit Testing in iOSUnit Testing in iOS
Unit Testing in iOS
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
 
Testacular
TestacularTestacular
Testacular
 
xUnit Style Database Testing
xUnit Style Database TestingxUnit Style Database Testing
xUnit Style Database Testing
 
Auto testing!
Auto testing!Auto testing!
Auto testing!
 

Viewers also liked (18)

Abô banho de ayran rennan peixe
Abô banho de ayran rennan peixeAbô banho de ayran rennan peixe
Abô banho de ayran rennan peixe
 
Os povos de oyó2011 uniabeu
Os povos de oyó2011 uniabeuOs povos de oyó2011 uniabeu
Os povos de oyó2011 uniabeu
 
Dicionriokimbu00assiuoft
Dicionriokimbu00assiuoftDicionriokimbu00assiuoft
Dicionriokimbu00assiuoft
 
Pajes cosmologia de um encontro
Pajes cosmologia de um encontroPajes cosmologia de um encontro
Pajes cosmologia de um encontro
 
As águas de
As águas deAs águas de
As águas de
 
O candomble
O candombleO candomble
O candomble
 
Apostila do bàbá oke tase
Apostila do bàbá oke taseApostila do bàbá oke tase
Apostila do bàbá oke tase
 
El camino de los orishas
El camino de los orishasEl camino de los orishas
El camino de los orishas
 
Los 16-mejis
Los 16-mejisLos 16-mejis
Los 16-mejis
 
Candomble
CandombleCandomble
Candomble
 
Santeria-magia-africana-migene-gonzalez-wippler
 Santeria-magia-africana-migene-gonzalez-wippler Santeria-magia-africana-migene-gonzalez-wippler
Santeria-magia-africana-migene-gonzalez-wippler
 
Nok culture
Nok cultureNok culture
Nok culture
 
Ifa
IfaIfa
Ifa
 
El Simbolismo Y La Iconografia En Santeria[1]
El Simbolismo Y La Iconografia En Santeria[1]El Simbolismo Y La Iconografia En Santeria[1]
El Simbolismo Y La Iconografia En Santeria[1]
 
El libro-ilustrado-signos-simbolos
El libro-ilustrado-signos-simbolosEl libro-ilustrado-signos-simbolos
El libro-ilustrado-signos-simbolos
 
Curso de-ifa
Curso de-ifaCurso de-ifa
Curso de-ifa
 
èRìndínlógún
èRìndínlógúnèRìndínlógún
èRìndínlógún
 
Tratado de ozain tomo3
Tratado de ozain tomo3Tratado de ozain tomo3
Tratado de ozain tomo3
 

Similar to Developer Tests - Things to Know (Vilnius JUG)

North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017Ortus Solutions, Corp
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Dror Helper
 
Software Testing
Software TestingSoftware Testing
Software TestingAdroitLogic
 
2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easierChristian Hujer
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctlyDror Helper
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLSteven Feuerstein
 
Testing with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifeTesting with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifePeter Gfader
 
Test Driven Development with Sql Server
Test Driven Development with Sql ServerTest Driven Development with Sql Server
Test Driven Development with Sql ServerDavid P. Moore
 
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF SummitOrtus Solutions, Corp
 
Testing And Drupal
Testing And DrupalTesting And Drupal
Testing And DrupalPeter Arato
 
Advance unittest
Advance unittestAdvance unittest
Advance unittestReza Arbabi
 
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016Gavin Pickin
 
Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It'sJim Lynch
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the UntestableMark Baker
 

Similar to Developer Tests - Things to Know (Vilnius JUG) (20)

North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctly
 
utPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQLutPLSQL: Unit Testing for Oracle PL/SQL
utPLSQL: Unit Testing for Oracle PL/SQL
 
Testing with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifeTesting with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs Life
 
Test Driven Development with Sql Server
Test Driven Development with Sql ServerTest Driven Development with Sql Server
Test Driven Development with Sql Server
 
Test Driven
Test DrivenTest Driven
Test Driven
 
TDD Best Practices
TDD Best PracticesTDD Best Practices
TDD Best Practices
 
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
 
Testing And Drupal
Testing And DrupalTesting And Drupal
Testing And Drupal
 
Advance unittest
Advance unittestAdvance unittest
Advance unittest
 
How to write Testable Javascript
How to write Testable JavascriptHow to write Testable Javascript
How to write Testable Javascript
 
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
 
Ansible testing
Ansible   testingAnsible   testing
Ansible testing
 
Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It's
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the Untestable
 

Recently uploaded

8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitter8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitterShivangiSharma879191
 
Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.eptoze12
 
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfElectronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfme23b1001
 
Past, Present and Future of Generative AI
Past, Present and Future of Generative AIPast, Present and Future of Generative AI
Past, Present and Future of Generative AIabhishek36461
 
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdfCCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdfAsst.prof M.Gokilavani
 
Introduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxIntroduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxk795866
 
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfCCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfAsst.prof M.Gokilavani
 
Introduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECHIntroduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECHC Sai Kiran
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...Chandu841456
 
Churning of Butter, Factors affecting .
Churning of Butter, Factors affecting  .Churning of Butter, Factors affecting  .
Churning of Butter, Factors affecting .Satyam Kumar
 
main PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidmain PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidNikhilNagaraju
 
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionSachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionDr.Costas Sachpazis
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleAlluxio, Inc.
 
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptxDecoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptxJoão Esperancinha
 
Concrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxConcrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxKartikeyaDwivedi3
 
computer application and construction management
computer application and construction managementcomputer application and construction management
computer application and construction managementMariconPadriquez1
 

Recently uploaded (20)

8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitter8251 universal synchronous asynchronous receiver transmitter
8251 universal synchronous asynchronous receiver transmitter
 
Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.Oxy acetylene welding presentation note.
Oxy acetylene welding presentation note.
 
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdfElectronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdf
 
Past, Present and Future of Generative AI
Past, Present and Future of Generative AIPast, Present and Future of Generative AI
Past, Present and Future of Generative AI
 
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdfCCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
 
Introduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxIntroduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptx
 
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfCCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
 
Introduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECHIntroduction to Machine Learning Unit-3 for II MECH
Introduction to Machine Learning Unit-3 for II MECH
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...
 
Churning of Butter, Factors affecting .
Churning of Butter, Factors affecting  .Churning of Butter, Factors affecting  .
Churning of Butter, Factors affecting .
 
main PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidmain PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfid
 
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
 
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective IntroductionSachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
Sachpazis Costas: Geotechnical Engineering: A student's Perspective Introduction
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
 
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptxDecoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
Decoding Kotlin - Your guide to solving the mysterious in Kotlin.pptx
 
young call girls in Green Park🔝 9953056974 🔝 escort Service
young call girls in Green Park🔝 9953056974 🔝 escort Serviceyoung call girls in Green Park🔝 9953056974 🔝 escort Service
young call girls in Green Park🔝 9953056974 🔝 escort Service
 
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptxExploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
 
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes  examplesPOWER SYSTEMS-1 Complete notes  examples
POWER SYSTEMS-1 Complete notes examples
 
Concrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptxConcrete Mix Design - IS 10262-2019 - .pptx
Concrete Mix Design - IS 10262-2019 - .pptx
 
computer application and construction management
computer application and construction managementcomputer application and construction management
computer application and construction management
 

Developer Tests - Things to Know (Vilnius JUG)

  • 1. Developer Tests Things to Know Vaidas Pilkauskas 2014 Vilnius JUG vaidas.pilkauskas@gmail.com
  • 2. me My hobbies ● developer at Wix.com ● main language - Scala ● main professional interest - developer communities If there is time left after my hobbies ● mountain bicycle rider, snowboarder ● consumer of rock music, contemporary art, etc
  • 3. me - how to contact me connect with me on LinkedIn http://lt.linkedin. com/pub/vaidas-pilkauskas/8/77/863/ add me on G+ https://www.google.com/+VaidasPilkauskas follow on Twitter @liucijus
  • 4. “We couldn’t understand why people without technical knowledge had to tell programmers “what” to do and, furthermore, they had to supervise “how” programmers did it.” Cristian Rennella http://qz.com/260846/why-our-startup-has-no-bosses-no-office-and-a-four-day-work-week/
  • 5. What this talk is about ● Things we argue about during code reviews ● Things that took me time to understand and prove that they are actually good way to go ● Small things we have no time to discuss during big talks
  • 6.
  • 7. “Legacy Code is code without Tests” Michael Feathers Working Effectively with Legacy Code
  • 8. So what is test? It is system’s exercise under predefined conditions and then verification of an expected outcome.
  • 9. Thing #1 Test structure
  • 10. Test phases Setup Exercise Verify Teardown
  • 11. Test phases in code Server server = new NotesServer(); // setup Note note = new Note("test note"); // setup Status status = server.add(note); // exercise assertEquals(SUCCESS, status); // verify server.shutdown(); // teardown
  • 12. Start everything in one method @Test public void serverShouldAddNoteSuccessfully() { Server server = new NotesServer(); // setup Note note = new Note("test note"); // setup Status status = server.add(note); // exercise assertEquals(SUCCESS, status); // verify server.shutdown(); // teardown }
  • 13. Refactor to lifecycle methods @Before public void before() { server = new NotesServer(); // setup note = new Note("test note"); // setup } @Test public void serverShouldAddNoteSuccessfully() { Status status = server.add(note); // exercise assertEquals(SUCCESS, status); // verify } @After public void after() { server.shutdown(); // teardown }
  • 14. DON’Ts - #1 Do not start from setup/teardown
  • 15. DON’Ts - #2 Do not mix setup code from different tests - shared code must be relevant to the tests that use it
  • 16. DON’Ts - #3 Setup and teardown are there to solve DRY problem and to help structure your test code
  • 17. How many colors are there in the picture? Source: Josef Albers Interaction of Color
  • 18. Context matters! Source: Josef Albers Interaction of Color
  • 19. Typical setup inside @Before @Before public void before() { server = new NotesServer(); // setup note = new Note("test note"); // setup } @Test public void serverShouldAddNoteSuccessfully() { Status status = server.add(note); // exercise assertEquals(SUCCESS, status); // verify } @After public void after() { server.shutdown(); // teardown }
  • 20. Setup pollution - #1 ● Every line in setup must be relevant to all tests.
  • 21. Setup pollution - #2 ● It is tempting to add additional setup tuning just to fix/enhance one test.
  • 22. Setup pollution - #3 ● Rich setup makes tests slow!
  • 23. Setup pollution - #4 ● Setup is to bootstrap your SUT.
  • 24. Setup pollution - #5 ● Setup hides details! Do not hide test preconditions.
  • 25. Setting up “job” inside test method @Before public void before() { server = new NotesServer(); // setup } @Test public void serverShouldAddNoteSuccessfully() { note = new Note("test note"); // setup Status status = server.add(note); // exercise assertEquals(SUCCESS, status); // verify }
  • 26. But then be more specific @Test public void serverShouldAddSingleLineNoteSuccesfully() { // * set up which is actual for the current method // * use scope specific name Note singleLineNote = new Note("test note"); // setup Status status = server.add(singleLineNote); // exercise assertEquals(SUCCESS, status); // verify }
  • 27. Give good names to setup methods @Before public void createNotesServer() { server = new NotesServer(); }
  • 28. Summary of test code organization ● DRY principle. ● Readability. BDD vs. DRY ● Consistency. Maintain the same style across your codebase. ● Complexity. It may dictate the way you go.
  • 29. Refactoring Refactoring is about improving the design of existing code. It is the process of changing a software system in such a way that it does not alter the external behavior of the code, yet improves its internal structure. Martin Fowler Refactoring: Improving the Design of Existing Code
  • 30. Thing #2 What do we test?
  • 31. Test behaviour not methods ● Think of a contract
  • 32. Test behaviour not methods ● Think of a contract ● And responsibilities
  • 33. Test behaviour not methods ● Think of a contract ● And responsibilities ● Specify requirements as tests
  • 34. Test behaviour not methods ● Think of a contract ● And responsibilities ● Specify requirements as tests ● Happens naturally when done in test-first approach
  • 36. Matchers ● Enhance readability ● Asserts on the right level of abstraction ● Encapsulate testing logic ● Reusable ● Detailed match error messages (do not leave them out in your custom matchers!)
  • 37. Matchers ● Enhance readability ● Asserts on the right level of abstraction ● Encapsulate testing logic ● Reusable ● Detailed match error messages (do not leave them out in your custom matchers!)
  • 38. Matcher libraries ● Hamcrest - standard matcher lib for JUnit ● AssertJ - fluent assertions (IDE friendly) ● Provides common matchers ● You can write your own custom matchers
  • 39. Hamcrest assertThat(frodo.getName(), equalTo("Frodo")); assertThat(frodo.getName(), is(equalTo("Frodo"))); assertThat(frodo.getName(), is("Frodo"));
  • 41. Thing #4 Custom matchers
  • 42. Custom matchers Are matchers that we write specifically for our projects.
  • 43. Custom matchers ● Help communicate test intention ● Abstract assertion logic in case standard matchers are not enough ● Are reusable and save time in large projects ● You may have a custom message to be more specific about test failure
  • 44. Custom matchers ● Help communicate test intention ● Abstract assertion logic in case standard matchers are not enough ● Are reusable and save time in large projects ● You may have a custom message to be more specific about test failure
  • 45. Custom matchers @Test public void shouldHaveIsbnGenerated() { Book book = new Book(1l, "5555", "A book"); assertThat(book, hasIsbn("1234")); }
  • 47. fail() In some cases (e.g. testing exceptions) you may want to force test to fail if some expected situation does not happen
  • 48. fail() try { // do stuff... fail("Exception not thrown"); } catch(Exception e){ assertTrue(e.hasSomeFlag()); }
  • 49. fail() ● Fundamentally not bad, but better use matchers for expected failure ● Matchers help to clarify test intention ● Don’t forget - expected behaviour is an opposite of a failing test
  • 50. Thing #6 Anti-pattern: The Ugly Mirror
  • 51. Anti-pattern: The Ugly Mirror @Test public void personToStringShouldIncludeNameAndSurname() { Person person = new Person("Vilkas", "Pilkas"); String expected = "Person[" + person.getName() + " " + person.getSurname() + "]" assertEquals(expected, person.toString()); }
  • 52. Anti-pattern: The Ugly Mirror @Test public void personToStringShouldIncludeNameAndSurname() { Person person = new Person("Vilkas", "Pilkas"); String expected = "Person[" + person.getName() + " " + person.getSurname() + "]" assertEquals(expected, person.toString()); }
  • 53. Anti-pattern: The Ugly Mirror @Test public void personToStringShouldIncludeNameAndSurname() { Person person = new Person("Vilkas", "Pilkas"); assertEquals("Person[Vilkas Pilkas]", person.toString()); }
  • 54. Thing #7 How to turn off the test?
  • 55. Why would you want to turn off the test?
  • 56. Why would you want to turn off the test? Well, because it fails… :)
  • 57. Ignoring tests ● Always use ignore/pending API from your test library (JUnit @Ignore)
  • 58. Ignoring tests ● Always use ignore/pending API from your test library (JUnit @Ignore) ● Do not comment out or false assert your test
  • 59. Ignoring tests ● Always use ignore/pending API from your test library (JUnit @Ignore) ● Do not comment out or false assert your test ● If you do not need a test - delete it
  • 60. Thing #8 What to do with exceptions?
  • 61. Exceptions ● If you can, use matchers instead of ○ @Test(expected=?) ○ try-catch approach
  • 62. JUnit expected exception @Test(expected=IndexOutOfBoundsException.class) public void shouldThrowIndexOutOfBoundsException() { ArrayList emptyList = new ArrayList(); Object o = emptyList.get(0); } //matcher in Specs2 (Scala) server.process(None) must throwA[NothingToProccess]
  • 63. try and catch public void shouldThrowIndexOutOfBoundsException() { ArrayList emptyList = new ArrayList(); try { Object o = emptyList.get(0); fail("Should throw IndexOutOfBoundsException"); } catch(IndexOutOfBoundsException e)){ //consider asserting message! } }
  • 65. catch-exception lib List myList = new ArrayList(); catchException(myList).get(1); assertThat(caughtException(), allOf( is(IndexOutOfBoundsException.class), hasMessage("Index: 1, Size: 0"), hasNoCause() ) );
  • 66. Exceptions ● What about ExpectedException Rule? ○ My personal opinion - not that intuitive ○ breaks arrange/act/assert flow
  • 67. ExpectedException rule @Rule public ExpectedException exception = ExpectedException.none(); @Test public void testExpectedException() { exception.expect(IllegalArgumentException.class); exception.expectMessage(containsString('Invalid age')); new Person('Vilkas', -1); } //Person constructor public Person(String name, int age) { if (age <= 0) throw new IllegalArgumentException('Invalid age:' + age); // ... }
  • 68. Thing #9 Testing with time
  • 69. Problem public class MyService { ... public void process(LocalDate date) { if (date.isBefore(LocalDate.now()) { ... } } }
  • 70. Testing with Time ● Design your system where time is a collaborator ● Inject test specific time provider in your test ○ constant time ○ slow time ○ boundary cases time
  • 71. Control time with Clock public class MyService { private Clock clock; // dependency inject ... public void process(LocalDate date) { if (date.isBefore(LocalDate.now(clock)) { ... } } }
  • 73. Collections - multiple properties to assert ● Is null? ● Size ● Order ● Content
  • 74. Collections ● Most of the time you want to assert on collection content
  • 75. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching
  • 76. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching ● Avoid incomplete assertions
  • 77. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching ● Avoid incomplete assertions ● Do not sort just because it is easier to assert!
  • 78. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching ● Avoid incomplete assertions ● Do not sort just because it is easier to assert! ● Multiple assertions are worse than single content assertion
  • 79. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching ● Avoid incomplete assertions ● Do not sort just because it is easier to assert! ● Multiple assertions are worse than single content assertion ● Unless you want to say something important in your test!
  • 80. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching ● Avoid incomplete assertions ● Do not sort just because it is easier to assert! ● Multiple assertions are worse than single content assertion ● Unless you want to say something important in your test! ● Use matchers!
  • 81. Collections ● Most of the time you want to assert on collection content ● Prefer exact content matching ● Avoid incomplete assertions ● Do not sort just because it is easier to assert! ● Multiple assertions are worse than single content assertion ● Unless you want to say something important in your test! ● Use matchers!
  • 83. Random values in tests ● Most of the time you do not want it
  • 84. Random values in tests ● Most of the time you do not want it ● Unless you depend on randomness a lot (eg. password generation*) *Thanks to Aleksandar Tomovski for a good example
  • 85. Random values in tests ● Most of the time you do not want it ● Unless you depend on randomness a lot ● Use property based testing (which is also hard)
  • 86. Random values in tests ● Most of the time you do not want it ● Unless you depend on randomness a lot ● Use property based testing (which is also hard) ● Do not make dummy values random
  • 87. What if we still need random cases?
  • 88. Generate Multiple Test Cases ● Quality over quantity
  • 89. Generate Multiple Test Cases ● Quality over quantity ● Think of boundary cases, that you may want to detect with random test
  • 90. Generate Multiple Test Cases ● Quality over quantity ● Think of boundary cases, that you may want to detect with random test ● Use parameterized tests
  • 91. Generate Multiple Test Cases ● Quality over quantity ● Think of boundary cases, that you may want to detect with random test ● Use parameterized tests ● Random is hard to repeat
  • 92. Generate Multiple Test Cases ● Quality over quantity ● Think of boundary cases, that you may want to detect with random test ● Use parameterized tests ● Random is hard to repeat ● Flickering tests
  • 93. Thing #12 How many assertions per test?
  • 94. How many assertions per test? ● Unit test - one assertion per test. Must be clear and readable ● Proper test should fail for exactly one reason ● End to end - best case one assertion per test, but more are allowed ● Consider custom matchers
  • 95. How many assertions per test? ● Unit test - one assertion per test. Must be clear and readable ● Proper test should fail for exactly one reason ● End to end - best case one assertion per test, but more are allowed ● Consider custom matchers
  • 96. Thing #13 Decoupling in End-to-end tests
  • 97. What can be better in this test [pseudocode] @Test shouldRetrieveUserByLogin() { String userJson = "{"username": "vaidas"}"; HttpRequest post = new Post("https://localhost:8080/users", userJson); HttpResponse postResp = HttpClient().execute(post); assertThat(postResp.status, is(200)); HttpRequest get = new Get("https://localhost:8080/users/vaidas"); HttpResponse getResp = HttpClient().execute(get); User user = mapper.readValue(getResp, User.class); assertThat(username, is("vaidas")); }
  • 98. Decoupling from low level details [pseudocode] @Test shouldRetrieveUserByUsername() { CreateUserResponse createResp = aCreateUserRequest().withUsername("vaidas").execute(); assertThat(createResp, hasStatus(OK)); GetUserResponse getResp = aGetUserRequest().withUsername("vaidas").execute(); assertThat(getResp, allOf(hasStatus(OK), hasUsername("vaidas"))); }
  • 99. Thoughts on end-to-end testing ● What is real e2e? REST vs. UI ● Testing by using system itself ● Vs. using low level DB driver to verify data persistence
  • 101. Comments in Test code ● Fundamentally good option to explain complicated parts, but: ● better use good method naming ● custom matcher ● do less, so that intention is clear ● comments are not so bad in isolated well named methods
  • 102. Summary ● Context matters ● Tests are controversial topic ● And very opinionated