SlideShare a Scribd company logo
1 of 84
Download to read offline
SOME
TESTING
The miseries and great
hardships of software testing
Sergio Arroyo Cuevas - @delr3ves
“I get paid for code that works, not for tests, so
my philosophy is to test as little as possible to
reach a given level of confidence …
-Kent Beck
WHO AM I?
WHO AM I?
MOTIVATION
DISCLAIMER
No silver bullets
What is testing about?
Getting feedback,
as often as we can
the sooner, the better
So please, send me your’s
@delr3ves
WHAT ARE WE TALKING ABOUT?
TAXONOMY
Taxonomy	
Scope	
Unit	
Integra3on	
System	
Visibillity	
Black	box	
White	box	
Inten3on	
Acceptance	
Func3onal	
Non	Func3onal	
…	
Technique	
Sta3c	
Dynamic	
Execu3on	
Automa3c	
Manual	
Google’s	
Small	
Medium	
Big
TESTS BY SCOPE
SCOPE
Database
PORT1 PORT2
ADAPTER1
UNIT TEST
DEPENDENCY INJECTION
➤Dependency:

A depends on B when A needs B to do
its job.
➤Injection:

Object (C) which uses A will tell A who
is B.
DEPENDENCY INJECTION
➤Dependency:

A depends on B when A needs B to do
its job.
➤Injection:

Object (C) which uses A will tell A who
is B.
DEPENDENCY INJECTION
C
A
B
➤A depends on B
➤C will tell A who is C
DEPENDENCY INJECTION
➤ Separate business logic from creation logic
➤Avoid use of new for service objects.
➤Value objects can be created any where.
➤ Service objects in charge to implement business
logic.
➤ IOC Container or factories in charge of creation
logic.
DEPENDENCY INJECTION
public UserService(UserValidator userValidator, UserDao userDao) {
this.userValidator = userValidator;
this.userDao = userDao;
}
public User createUser(User user) throws ValidationException {
this.userValidator.validate(user);
user = this.userDao.create(user);
return user;
}
public User createUser(User user) throws ValidationException {
UserValidator userValidator = new UserValidator(...);
userValidator.validate(user);
UserDao userDao = new UserDao(...);
user = userDao.create(user);
return user;
}
VS
DEPENDENCY INJECTION
public UserService(UserValidator userValidator, UserDao userDao) {
this.userValidator = userValidator;
this.userDao = userDao;
}
public User createUser(User user) throws ValidationException {
this.userValidator.validate(user);
user = this.userDao.create(user);
return user;
}
public User createUser(User user) throws ValidationException {
UserValidator userValidator = new UserValidator(...);
userValidator.validate(user);
UserDao userDao = new UserDao(...);
user = userDao.create(user);
return user;
}
VS
this sucks
TEST DOUBLES
TEST DOUBLES (FAKE)
Fake implementation in order to make test pass.
public UserDaoFake implements UserDao {
public User create(User user) {
return ...;
}
}
TEST DOUBLES (STUB)
Stubs provide canned answers to calls made during the test,
usually not responding at all to anything outside what’s
programmed in for the test.
UserValidator validatorMock = mock(UserValidator.class);
stub(validatorMock.validate(any(User.class)))
.toThrow(new ValidationException());
var validateCall = Sinon.stub();
validatorStub.withArgs(user)
.onFirstCall().returns(validationError);
var userValidator = {
validate: validatorStub;
}
OR WITH JS
TEST DOUBLES (SPY)
Spies are objects that also record some information based on how
they were called
var validatorSpy = Sinon.spy();
var userValidator = {
validate: validatorSpy;
}
userValidator.validate(user);
sinon.assert.calledOnce(validatorSpy);
sinon.assert.calledWith(validatorSpy, user);
OR WITH JS
UserValidator validatorSpy = spy(new UserValidator());
doThrow(new ValidationException())
.when(validatorSpy).validate();
TEST DOUBLES (SPY)
Spies are objects that also record some information based on how
they were called
var validatorSpy = Sinon.spy();
var userValidator = {
validate: validatorSpy;
}
userValidator.validate(user);
sinon.assert.calledOnce(validatorSpy);
sinon.assert.calledWith(validatorSpy, user);
OR WITH JS
UserValidator validatorSpy = spy(new UserValidator());
doThrow(new ValidationException())
.when(validatorSpy).validate();
TEST DOUBLES (MOCKS)
Informal: think in a Stub which is also a Spy.
It also responds with default values to non-explicitly declared
methods
UserValidator validatorMock = mock(UserValidator.class);
when(validatorMock.validate(any(User.class)))
.thenTrhow(new ValidationException());
verify(validatorMock).validate(any(User.class))
var validatorAPI = {validate: function()};
var validatorMock = Sinon.mock(validatorAPI);
validatorMock.expects('validate').once()
.withArgs(user).throws(validationError)
validatorAPI.validate(user)
validatorMock.verify()
OR WITH JS
INTEGRATION TEST WHICH WANT TO BE UNIT TESTS
FIRST(IT)
➤ Fast
➤Hundreds or thousands per second
➤ Isolates
➤Failure reasons become obvious
➤ Repeatable
➤In any order, any time
➤ Self-validating
➤No manual execution required
➤ Timely
➤Written before code
➤ Immutable*
➤SUT is in the same state after execute the tests
➤ Trusted*
➤When the test fails, the system fail and when the test works, the system works
INTEGRATION TEST WHICH WORKS WITH EXTERNAL SYSTEM
Database
Fast
Isolates
Repeatable
Self-Validating
Timely
Inmutable*
Trusted*
INTEGRATION TEST WHICH WORKS WITH EXTERNAL SYSTEM
Database
Fast
Isolates
Repeatable
Self-Validating
Timely
Inmutable*
Trusted*
INTEGRATION TEST WHICH USES THE UI
Database
Fast
Isolates
Repeatable
Self-Validating
Timely
Inmutable*
Trusted*
INTEGRATION TEST WHICH USES THE UI
Database
Fast
Isolates
Repeatable
Self-Validating
Timely
Inmutable*
Trusted*
SYSTEM TEST
Database
Fast
Isolates
Repeatable
Self-Validating
Timely
Inmutable*
Trusted*
SYSTEM TEST
Database
Fast
Isolates
Repeatable
Self-Validating
Timely
Inmutable*
Trusted*
WHO, WHEN AND WHERE RUN THE TESTS?
➤ Unit
➤ Owner: developer
➤ When: after every change
➤ Where: every computer
➤ Integration
➤ Owner: developer || QA team
➤ When: as part or after commit stage
➤ Where: devel and pre-pro environments
➤ System
➤ Owner: QA team
➤ When: after commit stage
➤ Where: devel and pre-pro environments
STRATEGIES
STATIC EVALUATION
➤Informal review
➤Formal review (inspection)
➤Checklists
➤Successive abstraction
➤Walkthrough
DYNAMIC EVALUATION
➤White box
➤Path Coverage
➤Statement Coverage
➤Condition Coverage
➤Function Coverage
➤Black box
➤Equivalence partitioning
➤Boundary values analysis
WHITE BOX (*-COVERAGE)
1. Get flow diagram of the SUT
2. Calculate cyclomatic complexity

3. Determine a data set which force going one path or another
4. Exercise the SUT with this dataset.
errors = []
if(user.name ==null||user.email == null) {
errors.push('mandatory fields not found');
}
//do the rest of whatever
for(var i=0; i < user.friends ; i++ ) {
errors.push(checkFriendShipt(user.friends[i]))
}
WHITE BOX (*-COVERAGE)
1. Get flow diagram of the SUT
2. Calculate cyclomatic complexity

3. Determine a data set which force going one path or another
4. Exercise the SUT with this dataset.
errors = []
if(user.name ==null||user.email == null) {
errors.push('mandatory fields not found');
}
//do the rest of whatever
for(var i=0; i < user.friends ; i++ ) {
errors.push(checkFriendShipt(user.friends[i]))
}
a
b c
d
…x
WHITE BOX (*-COVERAGE)
1. Get flow diagram of the SUT
2. Calculate cyclomatic complexity

3. Determine a data set which force going one path or another
4. Exercise the SUT with this dataset.
errors = []
if(user.name ==null||user.email == null) {
errors.push('mandatory fields not found');
}
//do the rest of whatever
for(var i=0; i < user.friends ; i++ ) {
errors.push(checkFriendShipt(user.friends[i]))
}
a
b c
d
…x
edges – nodes + 2 = predicate nodes +1 = number of regions = 4
BLACK BOX (PARTITIONING)
1. Identify equivalence classes
2. Select dataset:
1. Assign a unique value for every class
2. Select tests cases which cover the most
valid classes
3. Select tests cases which cover only one
invalid class at the same time
BLACK BOX (PARTITIONING)
1. Identify equivalence classes
2. Select dataset:
1. Assign a unique value for every class
2. Select tests cases which cover the most
valid classes
3. Select tests cases which cover only one
invalid class at the same time
BLACK BOX (PARTITIONING)
1. Identify equivalence classes
2. Select dataset:
1. Assign a unique value for every class
2. Select tests cases which cover the most
valid classes
3. Select tests cases which cover only one
invalid class at the same time
BLACK BOX (PARTITIONING)
Register
Username*
Password (6-10 chars including numbers)
BLACK BOX (PARTITIONING)
Username Password
U1: myNick P1: p4ssw0rd
U2: “empty” P2: p4ss
P3: l4rg3p4ssw0rd
P4: password
Register
Username*
Password (6-10 chars including numbers)
BLACK BOX (PARTITIONING)
Username Password
U1: myNick P1: p4ssw0rd
U2: “empty” P2: p4ss
P3: l4rg3p4ssw0rd
P4: password
Register
Username*
Password (6-10 chars including numbers)
Test Cases
myNick, p4ssw0rd √
myNick, p4ss X
myNick, l4rg3p4ssw0rd X
myNick, password X
“empty”, p4ssw0rd X
myNick, p4sw0rd_* X
BLACK BOX (METHODS WHICH TELL US A STORY)
VS
BLACK BOX (METHODS WHICH TELL US A STORY)
but if you hate exceptions…
AUTOMATIC TESTING
4 PHASES-TESTS
1. Set Up
2. Exercise
3. Verify
4. TearDown
TESTING FRAMEWORKS FAMILIES
➤X-Unit
➤@Before(Class)
➤@Test
➤@After(Class)
➤Spec
➤describe
➤ beforeEach
➤ it
➤ afterEach
➤Specification by example (A.K.A BDD)
➤Given
➤When
➤Then
XUNIT
@Before
public void setUp() {
this.userValidator = mock(UserValidator.class);
this.userDao = mock(UserDao.class);
this.userService = new UserService(userValidator, userDao);
}
@Test
public void createValidUserShouldNotFail() {
//Exercise
User expectedCreatedUser = new User("irrelevantUser");
when(userValidator.validate(any(User.class)));
when(userValidator.validate(any(User.class))).thenReturn(createdUser);
User createdUser = userService.create(new User());
//Assertions
assertThat(createdUser, equalTo(expectedCreatedUser));
}
@Test(expected=ValidationException)
public void createInvalidUserShouldFail() {
when(userValidator.validate(any(User.class)))
.thenReturn(new ValidationException());
userService.create(new User("irrelevantUser"));
}
@After
public void tearDown() {
//clean the state here
}
SPEC (SUITE PER CLASS)
describe('UserService test suite:', function(){
beforeEach(function(){
// setup the SUT
})
it('when create a valid user should not fail', function(){
// exercise + assertions
})
it('when create an invalid user should fail', function(){
// exercise + assertions
})
afterEach(function(){
// clean the state
})
})
• UserService test suite:
• When create a valid user should not fail √
• When create an invalid user should fail √
The report will look like:
SPEC (SUITE PER SETUP)
describe('UserService test suite:', function(){
describe("when create a valid user ", function() {
beforeEach(function(){
// setup and exercise
})
it('should return valid user', function(){
// partial assertions
})
it('should call validator', function(){
// partial assertions
})
it('should call dao', function(){
// partial assertions
})
afterEach(function(){
// clean the state
})
})
})
BDD (SPECIFICATION)
Feature: User registration
Scenario: User tries to register sending valid data so the system will create new account
Given the user has introduced <username> and <password> into the registration form
And has accepted terms and agreements
When send the registration from
Then the user with <username> should be created
Example:
| username | password |
| myNick | p4ssw0rd |
Scenario: User tries to register sending invalid data so the system will reject user
Given the user has introduced <username> and <password> into the registration form
And has accepted terms and agreements
When send the registration from
Then the system should notify <error>
Example:
| username | password | error |
| myNick | p4ss | password should have at least 6 characters |
| myNick | l4rg3p4ssword | password should have at less than 10 characters |
| myNick | password | password should contains at least a number |
| | p4ssword | username is mandatory |
BDD(IMPLEMENTATION)
@given("the user has introduced (w)+ and (w)+ into the
registration form")
public void populateForm(String username, String password) {
...
}
@given("has accepted terms and agreements")
public void acceptTerms() {
...
}
@when("send the registration from")
public void sendRegistrationForm() {
...
}
@then("the user with (w)+ should be created")
public void verifyUserIsCreated(String username) {
...
}
@then("the system should notify <error>")
public void verifyErrors(String error) {
...
}
TESTABLE DESIGN
NON-TESTABLE DESIGN SMELLS (BY MISKO HEVERY*)
➤Constructor does Real Work
➤Mixing business and creation logic
➤Class does too much work
➤Digging into collaborations
➤Brittle Global State & Singletons
*See http://misko.hevery.com/attachments/Guide-Writing Testable
Code.pdf
FROMNON-TESTABLETOTESTABLE
➤First of all, go to http://refactoring.com/
➤I suggest:
1. Add integration regression test.
2. Remove new from methods and ad it to constructors (this will prepare
your class for dependency injection).
3. Add a factory for Stateful services
4. Creates a constructor which receive every dependency your class will
need.
5. Remove static classes and methods (adding the new non-static as a class
dependency).
6. Add as much tests as you want to ;)
➤Important!!! Do it step by step
REMOVES NEW FOR DEPENDENCIES
public UserService() {
this(new UserValidator(), new UserDao());
}
public UserService(UserValidator userValidator, UserDao userDao) {
this.userValidator = userValidator;
this.userDao = userDao;
}
public User createUser(User user) throws ValidationException {
this.userValidator.validate(user);
user = this.userDao.create(user);
return user;
}
public User createUser(User user) throws ValidationException {
UserValidator userValidator = new UserValidator(...);
userValidator.validate(user);
UserDao userDao = new UserDao(...);
user = userDao.create(user);
return user;
}
TO
ADD FACTORIES FOR STATEFUL DEPENDENCIES
public UserService() {
this(new UserValidatorFactory(), new UserDao());
}
public UserService(UserValidator userValidatorFactory, UserDao
userDao) {
this.userValidatorFactory = userValidatorFactory;
this.userDao = userDao;
}
public User createUser(User user) throws ValidationException {
this.userValidatorFactory.getInstance(user).validate();
...
}
public User createUser(User user) throws ValidationException {
UserValidator userValidator = new UserValidator(user);
userValidator.validate();
...
}
TO
REMOVE STATIC CLASSES AND METHODS
class MyJsonSerializer {
public static String serialize(Object myObject) {
//put your magic here
}
}
class UserClient {
public void createUser(User user) {
Http.post(url, JsonSerizalizer.serialize(user));
}
}
REMOVE STATIC CLASSES AND METHODS
class MysonSerializer {
public String serialize(Object myObject) {
//put your magic here
}
}
class HttpClientWrapper {
public void post(String url, String body) {
Http.post(url, body);
}
}
class UserClient {
private JsonSerializer serializer;
private HttpClientWrapper httpClient
public UserClient() {
serializer = new JsonSerializer();
httpClient = new HttpClientWrapper();
}
public void createUser(User user) {
httpClient.post(url, serializer.serialize(user));
}
}
TIPS & TRICKS
QUESTIONS & STUPID QUESTIONS
➤I spend more time writing code to setup my SUT than
writing the test, how do you solve it?
➤I’ve never write a test, where can I start?
➤Should I verify every single interaction with my mocks?
➤Who tests the classes which test our classes?
➤Where I place my tests?
➤Could you be able to rewrite the code only reading the tests
definitions?
➤What is the minimum coverage should I expect for my code?
ISPENDMORETIMEWRITINGCODETOSETUPMYSUTTHANWRITINGTHETEST,HOWDOYOUSOLVEIT?
➤Read about Fixtures (Xunit Patterns is a
good reference).
➤Fresh fixtures
➤Shared fixtures
➤Persistent fixtures
➤Think about new ways of organising your
tests.
IDUPLICATETOOMUCHCODEONOBJECTSCREATION,MOCKSDEFINITIONANDASSERTION…
➤Writing a lot of code to initialize value objects?
➤Create DataBuilders / MotherObjects
➤Writing a lot of code to initialize mock/stub objects?
➤Create Mock“Mother”
➤Writing a lot of asserts (TDD purist says only one assertion)?
➤Create CustomAsserts
User user = new User("irrelevantUsername", "v4l1dP4ss",
irrelevant@myCompany.com", ...);
VS
User user = userMother.createValidUser();
assertNotNull(user.getUsername());
assertNotNull(user.getPassword());
assertNotNull(user.getEmail());
...
VS
assertContainsAllMandatoryData(user);
I’VENEVERWRITEATEST,WHERECANISTART?
I’ll bet you a beer that
you called it *[Util|
Helper]…
Database
PORT1 PORT2
ADAPTER1
SHOULD I VERIFY EVERY SINGLE INTERACTION WITH MY MOCKS?
It depends
But if you feel you have to, it’s probably due
to a bad design :S
WHO TESTS THE CLASSES WHICH TEST OUR CLASSES?
➤Exactly, this is why it’s so important our tests follow
KISS
Q&A
Place your question here!
@delr3ves
WHERE I PLACE MY TESTS?
➤Unit tests:
➤Test Class per Class
➤Test Class per SetUp (useful in Xunit frameworks)
➤Important naming convention (<ClassName>Test,
<TestSuite>IntegrationTest, …)
➤System tests:
➤Different project
WHERE I PLACE MY TESTS?
Java Project (Test Class per Class)
MyProject/
src/
main/
java/
com.groupId.artifactId.MyClass.java
resources/
test/
java/
com.groupId.artifactId.MyClassTest.java
com.groupId.artifactId.it.suite.MyTestCaseIntegrationTest.java
resources/
NodeJs Project
MyProject/
lib/
myClass.js
main.js
test/
ut/
/suite
it/
lib/
myClassTest.js
Java Project (Class per SetUp)
MyProject/
src/
main/
…
test/
java/
com.groupId.artifactId.myclass.<SetUp1>Test.java
com.groupId.artifactId.myclass.<SetUp2>Test.java
…
WHERE I PLACE MY TESTS?
IOS Project
MyIOSProject/
MyIOSProject/
... app code ...
MyIOSProjectTests/
... test code ...
Android Project
MyProject/
AndroidManifest.xml
res/
... (resources for main application)
src/
main/
… (source code for main application) …
test/
… (unit tests) …
androidTest/
… (android specific tests / UI, etc) …
tests/
AndroidManifest.xml
res/
… (resources for tests)
src/
... (source code for tests)
¿COULDYOUBEABLETOREWRITETHECODEONLYREADINGTHETESTSDEFINITIONS?

➤Tests (specially Black Box tests) should tell us an story.
➤Use well defined, and complete scenarios for system tests:
➤Use business vocabulary for acceptance tests:
public void testValidaterUser1 { ... }
VS
public void validate_user_with_no_password_should_throws_error { ... }
com.mycompany.artifactId.it.TestSteps ...
VS
com.mycompany.artifactId.it.usermanagement.UserCreationSteps ...
WHAT IS THE MINIMUM CODE COVERAGE?
➤“… test as little as possible to reach a given level of
confidence …”
➤Do not get obsess over test coverage, it’s a metric,
not a goal.
It depends
Q&A
Place your question here!
@delr3ves

More Related Content

What's hot

Grails unit testing
Grails unit testingGrails unit testing
Grails unit testingpleeps
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with MockitoRichard Paul
 
Java language fundamentals
Java language fundamentalsJava language fundamentals
Java language fundamentalsKapish Joshi
 
Advance unittest
Advance unittestAdvance unittest
Advance unittestReza Arbabi
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first stepsRenato Primavera
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for ProgrammersDavid Rodenas
 
(automatic) Testing: from business to university and back
(automatic) Testing: from business to university and back(automatic) Testing: from business to university and back
(automatic) Testing: from business to university and backDavid Rodenas
 
JMockit Framework Overview
JMockit Framework OverviewJMockit Framework Overview
JMockit Framework OverviewMario Peshev
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test frameworkAbner Chih Yi Huang
 
Android testing
Android testingAndroid testing
Android testingSean Tsai
 

What's hot (20)

Effective Unit Testing
Effective Unit TestingEffective Unit Testing
Effective Unit Testing
 
Testing in-groovy
Testing in-groovyTesting in-groovy
Testing in-groovy
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Java language fundamentals
Java language fundamentalsJava language fundamentals
Java language fundamentals
 
Advance unittest
Advance unittestAdvance unittest
Advance unittest
 
Grails Spock Testing
Grails Spock TestingGrails Spock Testing
Grails Spock Testing
 
Java Inheritance
Java InheritanceJava Inheritance
Java Inheritance
 
JUnit Pioneer
JUnit PioneerJUnit Pioneer
JUnit Pioneer
 
Unit test-using-spock in Grails
Unit test-using-spock in GrailsUnit test-using-spock in Grails
Unit test-using-spock in Grails
 
Java Programming - 03 java control flow
Java Programming - 03 java control flowJava Programming - 03 java control flow
Java Programming - 03 java control flow
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first steps
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
 
Exceptions
ExceptionsExceptions
Exceptions
 
GMock framework
GMock frameworkGMock framework
GMock framework
 
(automatic) Testing: from business to university and back
(automatic) Testing: from business to university and back(automatic) Testing: from business to university and back
(automatic) Testing: from business to university and back
 
Good Practices On Test Automation
Good Practices On Test AutomationGood Practices On Test Automation
Good Practices On Test Automation
 
JMockit Framework Overview
JMockit Framework OverviewJMockit Framework Overview
JMockit Framework Overview
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test framework
 
Android testing
Android testingAndroid testing
Android testing
 

Similar to #codemotion2016: Everything you should know about testing to go with @pedro_g_s, @flipper83 & @kinisoftware avoiding the hangover

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
 
DSR Testing (Part 1)
DSR Testing (Part 1)DSR Testing (Part 1)
DSR Testing (Part 1)Steve Upton
 
Test your tests with PIT framework
Test your tests with PIT frameworkTest your tests with PIT framework
Test your tests with PIT frameworkDarko Špoljarić
 
Unit Testing with JUnit4 by Ravikiran Janardhana
Unit Testing with JUnit4 by Ravikiran JanardhanaUnit Testing with JUnit4 by Ravikiran Janardhana
Unit Testing with JUnit4 by Ravikiran JanardhanaRavikiran J
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctlyDror Helper
 
Dont do it in android test automation
Dont do it in android test automationDont do it in android test automation
Dont do it in android test automationALEKSEITIURIN
 
Testing And Mxunit In ColdFusion
Testing And Mxunit In ColdFusionTesting And Mxunit In ColdFusion
Testing And Mxunit In ColdFusionDenard Springle IV
 
Assessing Unit Test Quality
Assessing Unit Test QualityAssessing Unit Test Quality
Assessing Unit Test Qualityguest268ee8
 
Introduzione allo Unit Testing
Introduzione allo Unit TestingIntroduzione allo Unit Testing
Introduzione allo Unit TestingStefano Ottaviani
 
Effective Unit Test Style Guide
Effective Unit Test Style GuideEffective Unit Test Style Guide
Effective Unit Test Style GuideJacky Lai
 
Java Unit Test - JUnit
Java Unit Test - JUnitJava Unit Test - JUnit
Java Unit Test - JUnitAktuğ Urun
 
Testing the waters of iOS
Testing the waters of iOSTesting the waters of iOS
Testing the waters of iOSKremizas Kostas
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 
lec-11 Testing.ppt
lec-11 Testing.pptlec-11 Testing.ppt
lec-11 Testing.pptdebjani12
 

Similar to #codemotion2016: Everything you should know about testing to go with @pedro_g_s, @flipper83 & @kinisoftware avoiding the hangover (20)

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
 
DSR Testing (Part 1)
DSR Testing (Part 1)DSR Testing (Part 1)
DSR Testing (Part 1)
 
Test your tests with PIT framework
Test your tests with PIT frameworkTest your tests with PIT framework
Test your tests with PIT framework
 
CTFL Module 04
CTFL Module 04CTFL Module 04
CTFL Module 04
 
Java Unit Testing
Java Unit TestingJava Unit Testing
Java Unit Testing
 
Unit Testing with JUnit4 by Ravikiran Janardhana
Unit Testing with JUnit4 by Ravikiran JanardhanaUnit Testing with JUnit4 by Ravikiran Janardhana
Unit Testing with JUnit4 by Ravikiran Janardhana
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctly
 
Dont do it in android test automation
Dont do it in android test automationDont do it in android test automation
Dont do it in android test automation
 
Testing And Mxunit In ColdFusion
Testing And Mxunit In ColdFusionTesting And Mxunit In ColdFusion
Testing And Mxunit In ColdFusion
 
Assessing Unit Test Quality
Assessing Unit Test QualityAssessing Unit Test Quality
Assessing Unit Test Quality
 
Unit testing - A&BP CC
Unit testing - A&BP CCUnit testing - A&BP CC
Unit testing - A&BP CC
 
Introduzione al TDD
Introduzione al TDDIntroduzione al TDD
Introduzione al TDD
 
Introduzione allo Unit Testing
Introduzione allo Unit TestingIntroduzione allo Unit Testing
Introduzione allo Unit Testing
 
Effective Unit Test Style Guide
Effective Unit Test Style GuideEffective Unit Test Style Guide
Effective Unit Test Style Guide
 
Java Unit Test - JUnit
Java Unit Test - JUnitJava Unit Test - JUnit
Java Unit Test - JUnit
 
Testing the waters of iOS
Testing the waters of iOSTesting the waters of iOS
Testing the waters of iOS
 
Qtp day 3
Qtp day 3Qtp day 3
Qtp day 3
 
Unit testing
Unit testingUnit testing
Unit testing
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
lec-11 Testing.ppt
lec-11 Testing.pptlec-11 Testing.ppt
lec-11 Testing.ppt
 

Recently uploaded

Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 

Recently uploaded (20)

Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 

#codemotion2016: Everything you should know about testing to go with @pedro_g_s, @flipper83 & @kinisoftware avoiding the hangover

  • 1. SOME TESTING The miseries and great hardships of software testing Sergio Arroyo Cuevas - @delr3ves
  • 2. “I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence … -Kent Beck
  • 10. the sooner, the better
  • 11. So please, send me your’s @delr3ves
  • 12. WHAT ARE WE TALKING ABOUT?
  • 13.
  • 16.
  • 20. DEPENDENCY INJECTION ➤Dependency:
 A depends on B when A needs B to do its job. ➤Injection:
 Object (C) which uses A will tell A who is B.
  • 21. DEPENDENCY INJECTION ➤Dependency:
 A depends on B when A needs B to do its job. ➤Injection:
 Object (C) which uses A will tell A who is B.
  • 22. DEPENDENCY INJECTION C A B ➤A depends on B ➤C will tell A who is C
  • 23.
  • 24. DEPENDENCY INJECTION ➤ Separate business logic from creation logic ➤Avoid use of new for service objects. ➤Value objects can be created any where. ➤ Service objects in charge to implement business logic. ➤ IOC Container or factories in charge of creation logic.
  • 25. DEPENDENCY INJECTION public UserService(UserValidator userValidator, UserDao userDao) { this.userValidator = userValidator; this.userDao = userDao; } public User createUser(User user) throws ValidationException { this.userValidator.validate(user); user = this.userDao.create(user); return user; } public User createUser(User user) throws ValidationException { UserValidator userValidator = new UserValidator(...); userValidator.validate(user); UserDao userDao = new UserDao(...); user = userDao.create(user); return user; } VS
  • 26. DEPENDENCY INJECTION public UserService(UserValidator userValidator, UserDao userDao) { this.userValidator = userValidator; this.userDao = userDao; } public User createUser(User user) throws ValidationException { this.userValidator.validate(user); user = this.userDao.create(user); return user; } public User createUser(User user) throws ValidationException { UserValidator userValidator = new UserValidator(...); userValidator.validate(user); UserDao userDao = new UserDao(...); user = userDao.create(user); return user; } VS this sucks
  • 28. TEST DOUBLES (FAKE) Fake implementation in order to make test pass. public UserDaoFake implements UserDao { public User create(User user) { return ...; } }
  • 29. TEST DOUBLES (STUB) Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test. UserValidator validatorMock = mock(UserValidator.class); stub(validatorMock.validate(any(User.class))) .toThrow(new ValidationException()); var validateCall = Sinon.stub(); validatorStub.withArgs(user) .onFirstCall().returns(validationError); var userValidator = { validate: validatorStub; } OR WITH JS
  • 30. TEST DOUBLES (SPY) Spies are objects that also record some information based on how they were called var validatorSpy = Sinon.spy(); var userValidator = { validate: validatorSpy; } userValidator.validate(user); sinon.assert.calledOnce(validatorSpy); sinon.assert.calledWith(validatorSpy, user); OR WITH JS UserValidator validatorSpy = spy(new UserValidator()); doThrow(new ValidationException()) .when(validatorSpy).validate();
  • 31. TEST DOUBLES (SPY) Spies are objects that also record some information based on how they were called var validatorSpy = Sinon.spy(); var userValidator = { validate: validatorSpy; } userValidator.validate(user); sinon.assert.calledOnce(validatorSpy); sinon.assert.calledWith(validatorSpy, user); OR WITH JS UserValidator validatorSpy = spy(new UserValidator()); doThrow(new ValidationException()) .when(validatorSpy).validate();
  • 32. TEST DOUBLES (MOCKS) Informal: think in a Stub which is also a Spy. It also responds with default values to non-explicitly declared methods UserValidator validatorMock = mock(UserValidator.class); when(validatorMock.validate(any(User.class))) .thenTrhow(new ValidationException()); verify(validatorMock).validate(any(User.class)) var validatorAPI = {validate: function()}; var validatorMock = Sinon.mock(validatorAPI); validatorMock.expects('validate').once() .withArgs(user).throws(validationError) validatorAPI.validate(user) validatorMock.verify() OR WITH JS
  • 33. INTEGRATION TEST WHICH WANT TO BE UNIT TESTS
  • 34. FIRST(IT) ➤ Fast ➤Hundreds or thousands per second ➤ Isolates ➤Failure reasons become obvious ➤ Repeatable ➤In any order, any time ➤ Self-validating ➤No manual execution required ➤ Timely ➤Written before code ➤ Immutable* ➤SUT is in the same state after execute the tests ➤ Trusted* ➤When the test fails, the system fail and when the test works, the system works
  • 35. INTEGRATION TEST WHICH WORKS WITH EXTERNAL SYSTEM Database Fast Isolates Repeatable Self-Validating Timely Inmutable* Trusted*
  • 36. INTEGRATION TEST WHICH WORKS WITH EXTERNAL SYSTEM Database Fast Isolates Repeatable Self-Validating Timely Inmutable* Trusted*
  • 37. INTEGRATION TEST WHICH USES THE UI Database Fast Isolates Repeatable Self-Validating Timely Inmutable* Trusted*
  • 38. INTEGRATION TEST WHICH USES THE UI Database Fast Isolates Repeatable Self-Validating Timely Inmutable* Trusted*
  • 41. WHO, WHEN AND WHERE RUN THE TESTS? ➤ Unit ➤ Owner: developer ➤ When: after every change ➤ Where: every computer ➤ Integration ➤ Owner: developer || QA team ➤ When: as part or after commit stage ➤ Where: devel and pre-pro environments ➤ System ➤ Owner: QA team ➤ When: after commit stage ➤ Where: devel and pre-pro environments
  • 43. STATIC EVALUATION ➤Informal review ➤Formal review (inspection) ➤Checklists ➤Successive abstraction ➤Walkthrough
  • 44. DYNAMIC EVALUATION ➤White box ➤Path Coverage ➤Statement Coverage ➤Condition Coverage ➤Function Coverage ➤Black box ➤Equivalence partitioning ➤Boundary values analysis
  • 45. WHITE BOX (*-COVERAGE) 1. Get flow diagram of the SUT 2. Calculate cyclomatic complexity
 3. Determine a data set which force going one path or another 4. Exercise the SUT with this dataset. errors = [] if(user.name ==null||user.email == null) { errors.push('mandatory fields not found'); } //do the rest of whatever for(var i=0; i < user.friends ; i++ ) { errors.push(checkFriendShipt(user.friends[i])) }
  • 46. WHITE BOX (*-COVERAGE) 1. Get flow diagram of the SUT 2. Calculate cyclomatic complexity
 3. Determine a data set which force going one path or another 4. Exercise the SUT with this dataset. errors = [] if(user.name ==null||user.email == null) { errors.push('mandatory fields not found'); } //do the rest of whatever for(var i=0; i < user.friends ; i++ ) { errors.push(checkFriendShipt(user.friends[i])) } a b c d …x
  • 47. WHITE BOX (*-COVERAGE) 1. Get flow diagram of the SUT 2. Calculate cyclomatic complexity
 3. Determine a data set which force going one path or another 4. Exercise the SUT with this dataset. errors = [] if(user.name ==null||user.email == null) { errors.push('mandatory fields not found'); } //do the rest of whatever for(var i=0; i < user.friends ; i++ ) { errors.push(checkFriendShipt(user.friends[i])) } a b c d …x edges – nodes + 2 = predicate nodes +1 = number of regions = 4
  • 48. BLACK BOX (PARTITIONING) 1. Identify equivalence classes 2. Select dataset: 1. Assign a unique value for every class 2. Select tests cases which cover the most valid classes 3. Select tests cases which cover only one invalid class at the same time
  • 49. BLACK BOX (PARTITIONING) 1. Identify equivalence classes 2. Select dataset: 1. Assign a unique value for every class 2. Select tests cases which cover the most valid classes 3. Select tests cases which cover only one invalid class at the same time
  • 50. BLACK BOX (PARTITIONING) 1. Identify equivalence classes 2. Select dataset: 1. Assign a unique value for every class 2. Select tests cases which cover the most valid classes 3. Select tests cases which cover only one invalid class at the same time
  • 52. BLACK BOX (PARTITIONING) Username Password U1: myNick P1: p4ssw0rd U2: “empty” P2: p4ss P3: l4rg3p4ssw0rd P4: password Register Username* Password (6-10 chars including numbers)
  • 53. BLACK BOX (PARTITIONING) Username Password U1: myNick P1: p4ssw0rd U2: “empty” P2: p4ss P3: l4rg3p4ssw0rd P4: password Register Username* Password (6-10 chars including numbers) Test Cases myNick, p4ssw0rd √ myNick, p4ss X myNick, l4rg3p4ssw0rd X myNick, password X “empty”, p4ssw0rd X myNick, p4sw0rd_* X
  • 54. BLACK BOX (METHODS WHICH TELL US A STORY) VS
  • 55. BLACK BOX (METHODS WHICH TELL US A STORY) but if you hate exceptions…
  • 57. 4 PHASES-TESTS 1. Set Up 2. Exercise 3. Verify 4. TearDown
  • 58. TESTING FRAMEWORKS FAMILIES ➤X-Unit ➤@Before(Class) ➤@Test ➤@After(Class) ➤Spec ➤describe ➤ beforeEach ➤ it ➤ afterEach ➤Specification by example (A.K.A BDD) ➤Given ➤When ➤Then
  • 59. XUNIT @Before public void setUp() { this.userValidator = mock(UserValidator.class); this.userDao = mock(UserDao.class); this.userService = new UserService(userValidator, userDao); } @Test public void createValidUserShouldNotFail() { //Exercise User expectedCreatedUser = new User("irrelevantUser"); when(userValidator.validate(any(User.class))); when(userValidator.validate(any(User.class))).thenReturn(createdUser); User createdUser = userService.create(new User()); //Assertions assertThat(createdUser, equalTo(expectedCreatedUser)); } @Test(expected=ValidationException) public void createInvalidUserShouldFail() { when(userValidator.validate(any(User.class))) .thenReturn(new ValidationException()); userService.create(new User("irrelevantUser")); } @After public void tearDown() { //clean the state here }
  • 60. SPEC (SUITE PER CLASS) describe('UserService test suite:', function(){ beforeEach(function(){ // setup the SUT }) it('when create a valid user should not fail', function(){ // exercise + assertions }) it('when create an invalid user should fail', function(){ // exercise + assertions }) afterEach(function(){ // clean the state }) }) • UserService test suite: • When create a valid user should not fail √ • When create an invalid user should fail √ The report will look like:
  • 61. SPEC (SUITE PER SETUP) describe('UserService test suite:', function(){ describe("when create a valid user ", function() { beforeEach(function(){ // setup and exercise }) it('should return valid user', function(){ // partial assertions }) it('should call validator', function(){ // partial assertions }) it('should call dao', function(){ // partial assertions }) afterEach(function(){ // clean the state }) }) })
  • 62. BDD (SPECIFICATION) Feature: User registration Scenario: User tries to register sending valid data so the system will create new account Given the user has introduced <username> and <password> into the registration form And has accepted terms and agreements When send the registration from Then the user with <username> should be created Example: | username | password | | myNick | p4ssw0rd | Scenario: User tries to register sending invalid data so the system will reject user Given the user has introduced <username> and <password> into the registration form And has accepted terms and agreements When send the registration from Then the system should notify <error> Example: | username | password | error | | myNick | p4ss | password should have at least 6 characters | | myNick | l4rg3p4ssword | password should have at less than 10 characters | | myNick | password | password should contains at least a number | | | p4ssword | username is mandatory |
  • 63. BDD(IMPLEMENTATION) @given("the user has introduced (w)+ and (w)+ into the registration form") public void populateForm(String username, String password) { ... } @given("has accepted terms and agreements") public void acceptTerms() { ... } @when("send the registration from") public void sendRegistrationForm() { ... } @then("the user with (w)+ should be created") public void verifyUserIsCreated(String username) { ... } @then("the system should notify <error>") public void verifyErrors(String error) { ... }
  • 65. NON-TESTABLE DESIGN SMELLS (BY MISKO HEVERY*) ➤Constructor does Real Work ➤Mixing business and creation logic ➤Class does too much work ➤Digging into collaborations ➤Brittle Global State & Singletons *See http://misko.hevery.com/attachments/Guide-Writing Testable Code.pdf
  • 66. FROMNON-TESTABLETOTESTABLE ➤First of all, go to http://refactoring.com/ ➤I suggest: 1. Add integration regression test. 2. Remove new from methods and ad it to constructors (this will prepare your class for dependency injection). 3. Add a factory for Stateful services 4. Creates a constructor which receive every dependency your class will need. 5. Remove static classes and methods (adding the new non-static as a class dependency). 6. Add as much tests as you want to ;) ➤Important!!! Do it step by step
  • 67. REMOVES NEW FOR DEPENDENCIES public UserService() { this(new UserValidator(), new UserDao()); } public UserService(UserValidator userValidator, UserDao userDao) { this.userValidator = userValidator; this.userDao = userDao; } public User createUser(User user) throws ValidationException { this.userValidator.validate(user); user = this.userDao.create(user); return user; } public User createUser(User user) throws ValidationException { UserValidator userValidator = new UserValidator(...); userValidator.validate(user); UserDao userDao = new UserDao(...); user = userDao.create(user); return user; } TO
  • 68. ADD FACTORIES FOR STATEFUL DEPENDENCIES public UserService() { this(new UserValidatorFactory(), new UserDao()); } public UserService(UserValidator userValidatorFactory, UserDao userDao) { this.userValidatorFactory = userValidatorFactory; this.userDao = userDao; } public User createUser(User user) throws ValidationException { this.userValidatorFactory.getInstance(user).validate(); ... } public User createUser(User user) throws ValidationException { UserValidator userValidator = new UserValidator(user); userValidator.validate(); ... } TO
  • 69. REMOVE STATIC CLASSES AND METHODS class MyJsonSerializer { public static String serialize(Object myObject) { //put your magic here } } class UserClient { public void createUser(User user) { Http.post(url, JsonSerizalizer.serialize(user)); } }
  • 70. REMOVE STATIC CLASSES AND METHODS class MysonSerializer { public String serialize(Object myObject) { //put your magic here } } class HttpClientWrapper { public void post(String url, String body) { Http.post(url, body); } } class UserClient { private JsonSerializer serializer; private HttpClientWrapper httpClient public UserClient() { serializer = new JsonSerializer(); httpClient = new HttpClientWrapper(); } public void createUser(User user) { httpClient.post(url, serializer.serialize(user)); } }
  • 72. QUESTIONS & STUPID QUESTIONS ➤I spend more time writing code to setup my SUT than writing the test, how do you solve it? ➤I’ve never write a test, where can I start? ➤Should I verify every single interaction with my mocks? ➤Who tests the classes which test our classes? ➤Where I place my tests? ➤Could you be able to rewrite the code only reading the tests definitions? ➤What is the minimum coverage should I expect for my code?
  • 73. ISPENDMORETIMEWRITINGCODETOSETUPMYSUTTHANWRITINGTHETEST,HOWDOYOUSOLVEIT? ➤Read about Fixtures (Xunit Patterns is a good reference). ➤Fresh fixtures ➤Shared fixtures ➤Persistent fixtures ➤Think about new ways of organising your tests.
  • 74. IDUPLICATETOOMUCHCODEONOBJECTSCREATION,MOCKSDEFINITIONANDASSERTION… ➤Writing a lot of code to initialize value objects? ➤Create DataBuilders / MotherObjects ➤Writing a lot of code to initialize mock/stub objects? ➤Create Mock“Mother” ➤Writing a lot of asserts (TDD purist says only one assertion)? ➤Create CustomAsserts User user = new User("irrelevantUsername", "v4l1dP4ss", irrelevant@myCompany.com", ...); VS User user = userMother.createValidUser(); assertNotNull(user.getUsername()); assertNotNull(user.getPassword()); assertNotNull(user.getEmail()); ... VS assertContainsAllMandatoryData(user);
  • 75. I’VENEVERWRITEATEST,WHERECANISTART? I’ll bet you a beer that you called it *[Util| Helper]… Database PORT1 PORT2 ADAPTER1
  • 76. SHOULD I VERIFY EVERY SINGLE INTERACTION WITH MY MOCKS? It depends But if you feel you have to, it’s probably due to a bad design :S
  • 77. WHO TESTS THE CLASSES WHICH TEST OUR CLASSES? ➤Exactly, this is why it’s so important our tests follow KISS
  • 78. Q&A Place your question here! @delr3ves
  • 79. WHERE I PLACE MY TESTS? ➤Unit tests: ➤Test Class per Class ➤Test Class per SetUp (useful in Xunit frameworks) ➤Important naming convention (<ClassName>Test, <TestSuite>IntegrationTest, …) ➤System tests: ➤Different project
  • 80. WHERE I PLACE MY TESTS? Java Project (Test Class per Class) MyProject/ src/ main/ java/ com.groupId.artifactId.MyClass.java resources/ test/ java/ com.groupId.artifactId.MyClassTest.java com.groupId.artifactId.it.suite.MyTestCaseIntegrationTest.java resources/ NodeJs Project MyProject/ lib/ myClass.js main.js test/ ut/ /suite it/ lib/ myClassTest.js Java Project (Class per SetUp) MyProject/ src/ main/ … test/ java/ com.groupId.artifactId.myclass.<SetUp1>Test.java com.groupId.artifactId.myclass.<SetUp2>Test.java …
  • 81. WHERE I PLACE MY TESTS? IOS Project MyIOSProject/ MyIOSProject/ ... app code ... MyIOSProjectTests/ ... test code ... Android Project MyProject/ AndroidManifest.xml res/ ... (resources for main application) src/ main/ … (source code for main application) … test/ … (unit tests) … androidTest/ … (android specific tests / UI, etc) … tests/ AndroidManifest.xml res/ … (resources for tests) src/ ... (source code for tests)
  • 82. ¿COULDYOUBEABLETOREWRITETHECODEONLYREADINGTHETESTSDEFINITIONS?
 ➤Tests (specially Black Box tests) should tell us an story. ➤Use well defined, and complete scenarios for system tests: ➤Use business vocabulary for acceptance tests: public void testValidaterUser1 { ... } VS public void validate_user_with_no_password_should_throws_error { ... } com.mycompany.artifactId.it.TestSteps ... VS com.mycompany.artifactId.it.usermanagement.UserCreationSteps ...
  • 83. WHAT IS THE MINIMUM CODE COVERAGE? ➤“… test as little as possible to reach a given level of confidence …” ➤Do not get obsess over test coverage, it’s a metric, not a goal. It depends
  • 84. Q&A Place your question here! @delr3ves