SlideShare a Scribd company logo
Write testable code
best practices and common smells
Why you should invest time to write testable code
Testable code is easy to
maintain on the long run
Easy to test code makes the maintenance
straightforward for developers and cheap for
the stakeholders
Coding with testability in mind will drive the
code towards a flexible design, that allows
safe refactoring
2
You will write tests also
after the main release
Most projects deliver software first,
without a full test coverage
Unit tests are added also later, during
consolidation phases, every time you fix a
bug, or you implement a change request
Most likely other developers will also
extend and test your code
I am Marian Wamsiedel
I work as a java developer
mainly in java enterprise
projects
You can find me at
marian.wamsiedel@gmail.com
3HELLO!
What makes your code easy to test
Loose
coupling No static
calls
4
Logic free
constructors
Compact
data
creation
Clear intent
What makes your code easy to test
Loose
coupling No static
calls
5
Logic free
constructors
Compact
data
creation
Clear intent
Ensure components loose coupling
Hard coupling severely damages testability
Loose coupling
➢
Replace creation of new objects with
dependency injection
➢
Inject all collaborators in the constructor
➢
If forced by the api, create fake constructors
visible from the unit tests
➢
Handle the bloated constructors nicely
7
Loose coupling, dependency injection instead of objects creation
● Each unit test will also create a “real” object if the
productive code instantiates a collaborator
● The object creation is a potential slow operation
● A created collaborator can not be faked (mocked,
or stubbed) in the test
8
Loose coupling, dependency injection instead of objects creation
● In order to simulate the collaborators behavior, the
tests are forced to fake second/third level
collaborators, or to set up values in a database
● The system dependencies are not transparent.
They are hidden in the implementation, not
declared in the public API
● Replace each “new” call with dependency injection
9
Loose coupling, dependency injection instead of objects creation
● The simple knowledge of second level
collaborators disqualifies the test as “unit test”
● If the productive code instantiates a logic class,
like a calculator, the tests will check the behavior
of both classes, mixing the concepts
● Changes in the collaborator's behavior can break
also the main class tests, leading to brittle tests
10
Loose coupling, dependency injection instead of objects creation
● Example – instantiated collaborator
public int averageCustomersAge(){
return new CustomerRepository().customers().stream()
.mapToInt(Customer::age)
.average().orElse(0d);}
● The unit test should now fake the result of the
call: new CustomerRepository().customers(),
which requires know how about customer
repository collaborators
11
Loose coupling, dependency injection instead of objects creation
● Example – injected collaborator
class CustomerLogic {
private final CustomerRepository repository;
CustomerLogic(final CustomerRepository customerRepository){
this.repository = customerRepository;}
int averageCustomersAge(){
return repository.customers().stream()
.mapToInt(Customer::age)
.average().orElse(0d);}
}
12
Loose coupling, dependency injection instead of objects creation
● Example – injected collaborator, test
@Test
public void shouldCalculateAverageCorrectly(){
when(repository.customers()).thenReturn(
asList(
Customer.withAge(20),
Customer.withAge(30))
);
final CustomerLogic underTest = new CustomerLogic(repository);
assertThat(
underTest.averageCustomersAge(),
is(25d));
}
13
Loose coupling
➢
Replace creation of new objects with
dependency injection
➢
Inject all collaborators in the constructor
➢
If forced by the api, create fake constructors
visible from the unit tests
➢
Handle the bloated constructors nicely
14
Loose coupling, inject collaborators in constructor
● The dependencies are visible in the class API
● It is really easy to write unit tests. When you
instantiate the component under test, you just call
the constructor, passing mocks, or test doubles as
arguments
● You can design immutable classes
15
Loose coupling, dependency injection instead of objects creation
● It indicates possible design flaws: is your class
still cohesive and follows the single responsibility
principle, if it has way too many collaborators?
● Avoid the field injection, even if your dependency
injection system allows it
16
Loose coupling
➢
Replace creation of new objects with
dependency injection
➢
Inject all collaborators in the constructor
➢
If forced by the api, create fake constructors
visible from the unit tests
➢
Handle the bloated constructors nicely
17
Loose coupling, fake test constructors
● If the API forces a constructor signature that does
not allow the injection of the collaborators, do not
unit test this main constructor
● Create a package-private constructor, that
accepts all collaborators as parameters
● Unit test this package-private constructor
18
Loose coupling, fake test constructors
● Example, difficult to test version
// The signature is forced by the API, cannot be changed
public MessageCenter(final String id){
super(id);
this.notificationService = new NotificationService();
this.mailService = new MailService();
}
● This constructor cannot be unit tested in a
simple, clean way
19
Loose coupling, fake test constructors
● Example, the easy to test version
// The signature forced by the API, cannot be changed
public MessageCenter(final String id){
this (id, new NotificationService(), new MailService());
}
// You can easy test this constructor
MessageCenter(final String id,
final NotificationService notificationService,
final MailService mailService) {...}
20
Loose coupling
➢
Replace creation of new objects with
dependency injection
➢
Inject all collaborators in the constructor
➢
If forced by the api, create fake constructors
visible from the unit tests
➢
Handle the bloated constructors nicely
21
Loose coupling, handle bloated constructor
● Injecting all the dependencies in the constructor
can lead to a long parameter list
● A long parameter list can signalize lack of
cohesion and therefore you should consider
refactoring the class in order to split the concerns
22
Loose coupling, handle bloated constructor
● If refactoring is not required, search for
parameters that belong together:
– Group the components into a new class. Use a
single instance of the class as constructor
argument
– Use composition. Inject one object into another
and use a single instance of the main class as
constructor argument
23
What makes your code easy to test
Loose
coupling No static
calls
24
Logic free
constructors
Compact
data
creation
Clear intent
Logic free constructors are easy to test
Avoid smart, or hard working constructors
Design logic free constructors
● The code in the constructor is run by each test. A
“hard working” constructor makes your tests slow
● Avoid any object creation in the constructor, like
connections, entity managers, or providers
● Any “new” call in constructor could trigger a
pyramid of calls, that will make your tests slow
and brittle
26
Design logic free constructors
● The constructors should ideally just initialize
instance variables with constructor arguments
values
● The usage of “init()” blocks, post construct
blocks, or static code initializers is cheating and
we know it
27
What makes your code easy to test
Loose
coupling No static
calls
28
Logic free
constructors
Compact
data
creation
Clear intent
29
The instance method calls are easy to fake
Use them as long as possible, avoid static calls
Static calls
➢
Collaborators are not visible in your API
➢
Collaborators behavior can change without
notice
➢
Static calls can force you to register transitive
dependencies
➢
Singletons are dependencies
30
No static calls, collaborators not declared in API
● The collaborators that receive the static call are
not declared transparently, in the public API
● The static calls are like secret communication
channels to unknown entities
● Replacing the static calls with instance calls on
injected collaborators make the API clear
31
Static calls
➢
Collaborators are not visible in your API
➢
Collaborators behavior can change without
notice
➢
Static calls can force you to register transitive
dependencies
➢
Singletons are dependencies
32
No static calls, collaborator's behavior changes
● Since not all the mocking frameworks support
static calls, you might end up running real static
calls and faking some second level dependencies
● If the receiver of a static call delegates to another
collaborator, the mock rules will not be triggered
● The tests can fail with no reason (false positives)
and are no longer a refactoring safety net
33
Static calls
➢
Collaborators are not visible in your API
➢
Collaborators behavior can change without
notice
➢
Static calls can force you to register transitive
dependencies
➢
Singletons are dependencies
34
No static calls, transitive dependencies
● If the tests run real static calls, you might be
forced to register in the test also the static
collaborators dependencies
● Example: if the collaborator uses a globally
defined WebSession object, your test should also
register it in the ThreadLocal
● You might be forced to run the test in a suite
35
Static calls
➢
Collaborators are not visible in your API
➢
Collaborators behavior can change without
notice
➢
Static calls can force you to register transitive
dependencies
➢
Singletons are dependencies
36
No static calls, singletons
● Singletons are provided over a static factory
method call, that can not be mocked. You need to
mock the singleton dependencies
● Since the singleton behavior can change without
notice, you should treat it as a dependency
● Prefer injecting beans with singleton scope. Their
method calls can also be cached
37
What makes your code easy to test
Loose
coupling No static
calls
38
Logic free
constructors
Compact
data
creation
Clear intent
39
The tests need to create data
Builders are better than setters
Compact data creation
● It is really difficult to create complex test data, if
the domain classes expose only setters and
allArgsConstructors
● If you control the domain classes, make sure you
design them small and cohesive
● Consider providing builders and / or “with”-ers as
alternative to setters
40
Compact data creation
● Setters mean mutable objects. Use them only if
you really need data objects
● The creation of Java beans in the test leads to
long set up methods, that are hard to follow and
boring to read
● AllArgsConstructor calls force the tests to provide
values for all the bean fields, even if irrelevant
41
Compact data creation
● The builders can create immutable objects
● The builders let you initialize just the relevant
fields
● The builders can also initialize behind the scene
fields with default values, avoiding duplicated
code in each test method
42
Compact data creation
● The builders and “with”-ers calls can be chained,
increasing the code readability
● Example - “with”-ers
Customer regular = customer()
.withName(“name”)
.withId(123L)
.withSubscription(456L);
43
Compact data creation
● Example – builder:
Customer company = Customer.companyBuilder()
.name(“company A”)
.id(1234567L)
.taxAddress(someAddress())
.mainOfficeAddress(someOtherAddress())
.build();
Customer private = Customer.privateBuilder()
.name(“Joe”)
.birthday(“1970-01-01”)
.homeAddress(“some address”)
.postalAddress(“some other address”)
.build();
44
What makes your code easy to test
Loose
coupling No static
calls
45
Logic free
constructors
Compact
data
creation
Clear intent
46
Write clear code, not smart one
The tests and the readers of your code will be thankful
Clear intent, no magic
● There is way more time invested in maintenance,
than in the original code development
● Other developers will most likely extend your
code
● The tests should document the code. The good
code is simple and its intent is clear. Avoid smart
tricks and hidden functionality
47
Clear intent, no magic
● Smell: getter with extra functionality
class UserMonitor {
private User currentUser;
User currentUser(){
if (this.currentUser == null) {
this.currentUser = loadUser();
validationService.check(currentUser);
outboundService.scan(currentUser);
}
}
}
● A whole jungle is hidden behind the getter call
48
Clear intent, no magic
● Smell: return default values if not initialized
class User {
private final List<Subscription> subscriptions;
List<Subscription> subscriptions(){
return subscriptions == null ? trial() : subscriptions;}}
● The test code would check if there is a trial
subscription for every user, that has no
subscriptions
49
Clear intent, no magic
● Smell: add data to match client requirements
class ServiceLayerMapper {
// The user interface algorithm needs an extra empty product!
public List<Product> mapBuyedItems(){
return asList(
emptyProduct(),
mappedItems(purchasedItems())
);
}
● The test code will check if there is always an item
in the basket, if the user does not buy anything
50
CREDITS
● Growing Object-oriented software, guided by tests (Steve Freeman, Nat
Pryce)
● Stephen Colebourne, Code generating beans in java:
https://www.slideshare.net/scolebourne/code-generating-beans-in-java
● Misko Hevery, testability explorer blog:
http://misko.hevery.com/code-reviewers-guide/
http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/
● Effective Java, Joshua Bloch
● Elegant objects, Yegor Bugayenko
51
CREDITS
● Presentation template by SlidesCarnival
● Photographs by Unsplash
● Diverse device hand photos by Facebook Design Resources
● www.freepik.com photos:
– Designed by mrsiraphol / Freepik
– Designed by ijeab / Freepik
– Designed by Onlyyouqj / Freepik
– Designed by ijeab / Freepik
– Designed by Dashu83 / Freepik
52
Any questions?
You can find me at:
marian.wamsiedel@gmail.com
53THANKS!

More Related Content

Similar to Write testable code in java, best practices

Test driven development - Zombie proof your code
Test driven development - Zombie proof your codeTest driven development - Zombie proof your code
Test driven development - Zombie proof your code
Pascal Larocque
 
Software Testing
Software TestingSoftware Testing
Software Testing
AdroitLogic
 
Testing Rest with Spring by Kostiantyn Baranov (Senior Software Engineer, Gl...
Testing Rest with Spring  by Kostiantyn Baranov (Senior Software Engineer, Gl...Testing Rest with Spring  by Kostiantyn Baranov (Senior Software Engineer, Gl...
Testing Rest with Spring by Kostiantyn Baranov (Senior Software Engineer, Gl...
GlobalLogic Ukraine
 
Indy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-muleIndy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-mule
ikram_ahamed
 
Spring Test Framework
Spring Test FrameworkSpring Test Framework
Spring Test Framework
GlobalLogic Ukraine
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the Untestable
Mark Baker
 
Software testing ... who’s responsible is it?
Software testing ... who’s responsible is it?Software testing ... who’s responsible is it?
Software testing ... who’s responsible is it?
Manjula03809891
 
Software testing ... who is responsible for it?
Software testing ... who is responsible for it?Software testing ... who is responsible for it?
Software testing ... who is responsible for it?
Manjula Piyumal
 
Dependency injection using Google guice
Dependency injection using Google guiceDependency injection using Google guice
Dependency injection using Google guice
Aman Verma
 
What is the best approach to tdd
What is the best approach to tddWhat is the best approach to tdd
What is the best approach to tdd
Red Hat
 
Writing useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you buildWriting useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you build
Andrei Sebastian Cîmpean
 
Loopt unit test experiences
Loopt unit test experiencesLoopt unit test experiences
Loopt unit test experiences
Heine Frifeldt
 
Keeping code clean
Keeping code cleanKeeping code clean
Keeping code clean
Brett Child
 
Testing strategies in microservices
Testing strategies in microservicesTesting strategies in microservices
Testing strategies in microservices
GeekNightHyderabad
 
Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)
Abhijeet Vaikar
 
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
DicodingEvent
 
Automock: Interaction-Based Mock Code Generation
Automock: Interaction-Based Mock Code GenerationAutomock: Interaction-Based Mock Code Generation
Automock: Interaction-Based Mock Code Generation
Sabrina Souto
 
Testing, a pragmatic approach
Testing, a pragmatic approachTesting, a pragmatic approach
Testing, a pragmatic approach
Enrico Da Ros
 
Unit Testing Fundamentals
Unit Testing FundamentalsUnit Testing Fundamentals
Unit Testing Fundamentals
Richard Paul
 
Wading through treacle? Escape the integration syrup with contract tests
Wading through treacle? Escape the integration syrup with contract testsWading through treacle? Escape the integration syrup with contract tests
Wading through treacle? Escape the integration syrup with contract tests
Stefan Smith
 

Similar to Write testable code in java, best practices (20)

Test driven development - Zombie proof your code
Test driven development - Zombie proof your codeTest driven development - Zombie proof your code
Test driven development - Zombie proof your code
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
Testing Rest with Spring by Kostiantyn Baranov (Senior Software Engineer, Gl...
Testing Rest with Spring  by Kostiantyn Baranov (Senior Software Engineer, Gl...Testing Rest with Spring  by Kostiantyn Baranov (Senior Software Engineer, Gl...
Testing Rest with Spring by Kostiantyn Baranov (Senior Software Engineer, Gl...
 
Indy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-muleIndy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-mule
 
Spring Test Framework
Spring Test FrameworkSpring Test Framework
Spring Test Framework
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the Untestable
 
Software testing ... who’s responsible is it?
Software testing ... who’s responsible is it?Software testing ... who’s responsible is it?
Software testing ... who’s responsible is it?
 
Software testing ... who is responsible for it?
Software testing ... who is responsible for it?Software testing ... who is responsible for it?
Software testing ... who is responsible for it?
 
Dependency injection using Google guice
Dependency injection using Google guiceDependency injection using Google guice
Dependency injection using Google guice
 
What is the best approach to tdd
What is the best approach to tddWhat is the best approach to tdd
What is the best approach to tdd
 
Writing useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you buildWriting useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you build
 
Loopt unit test experiences
Loopt unit test experiencesLoopt unit test experiences
Loopt unit test experiences
 
Keeping code clean
Keeping code cleanKeeping code clean
Keeping code clean
 
Testing strategies in microservices
Testing strategies in microservicesTesting strategies in microservices
Testing strategies in microservices
 
Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)
 
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
Play with Testing on Android - Gilang Ramadhan (Academy Content Writer at Dic...
 
Automock: Interaction-Based Mock Code Generation
Automock: Interaction-Based Mock Code GenerationAutomock: Interaction-Based Mock Code Generation
Automock: Interaction-Based Mock Code Generation
 
Testing, a pragmatic approach
Testing, a pragmatic approachTesting, a pragmatic approach
Testing, a pragmatic approach
 
Unit Testing Fundamentals
Unit Testing FundamentalsUnit Testing Fundamentals
Unit Testing Fundamentals
 
Wading through treacle? Escape the integration syrup with contract tests
Wading through treacle? Escape the integration syrup with contract testsWading through treacle? Escape the integration syrup with contract tests
Wading through treacle? Escape the integration syrup with contract tests
 

Recently uploaded

14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision
ShulagnaSarkar2
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
XfilesPro
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.
Maitrey Patel
 
Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)
Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)
Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)
safelyiotech
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
dakas1
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
Quickdice ERP
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
Marcin Chrost
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
Bert Jan Schrijver
 
What’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete RoadmapWhat’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete Roadmap
Envertis Software Solutions
 
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSISDECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
Tier1 app
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
Patrick Weigel
 
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
kalichargn70th171
 
ppt on the brain chip neuralink.pptx
ppt  on   the brain  chip neuralink.pptxppt  on   the brain  chip neuralink.pptx
ppt on the brain chip neuralink.pptx
Reetu63
 
INTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLES
INTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLESINTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLES
INTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLES
anfaltahir1010
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
brainerhub1
 
The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024
Yara Milbes
 

Recently uploaded (20)

14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.
 
Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)
Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)
Safelyio Toolbox Talk Softwate & App (How To Digitize Safety Meetings)
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
 
What’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete RoadmapWhat’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete Roadmap
 
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSISDECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
 
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
The Key to Digital Success_ A Comprehensive Guide to Continuous Testing Integ...
 
ppt on the brain chip neuralink.pptx
ppt  on   the brain  chip neuralink.pptxppt  on   the brain  chip neuralink.pptx
ppt on the brain chip neuralink.pptx
 
INTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLES
INTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLESINTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLES
INTRODUCTION TO AI CLASSICAL THEORY TARGETED EXAMPLES
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
 
The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024
 

Write testable code in java, best practices

  • 1. Write testable code best practices and common smells
  • 2. Why you should invest time to write testable code Testable code is easy to maintain on the long run Easy to test code makes the maintenance straightforward for developers and cheap for the stakeholders Coding with testability in mind will drive the code towards a flexible design, that allows safe refactoring 2 You will write tests also after the main release Most projects deliver software first, without a full test coverage Unit tests are added also later, during consolidation phases, every time you fix a bug, or you implement a change request Most likely other developers will also extend and test your code
  • 3. I am Marian Wamsiedel I work as a java developer mainly in java enterprise projects You can find me at marian.wamsiedel@gmail.com 3HELLO!
  • 4. What makes your code easy to test Loose coupling No static calls 4 Logic free constructors Compact data creation Clear intent
  • 5. What makes your code easy to test Loose coupling No static calls 5 Logic free constructors Compact data creation Clear intent
  • 6. Ensure components loose coupling Hard coupling severely damages testability
  • 7. Loose coupling ➢ Replace creation of new objects with dependency injection ➢ Inject all collaborators in the constructor ➢ If forced by the api, create fake constructors visible from the unit tests ➢ Handle the bloated constructors nicely 7
  • 8. Loose coupling, dependency injection instead of objects creation ● Each unit test will also create a “real” object if the productive code instantiates a collaborator ● The object creation is a potential slow operation ● A created collaborator can not be faked (mocked, or stubbed) in the test 8
  • 9. Loose coupling, dependency injection instead of objects creation ● In order to simulate the collaborators behavior, the tests are forced to fake second/third level collaborators, or to set up values in a database ● The system dependencies are not transparent. They are hidden in the implementation, not declared in the public API ● Replace each “new” call with dependency injection 9
  • 10. Loose coupling, dependency injection instead of objects creation ● The simple knowledge of second level collaborators disqualifies the test as “unit test” ● If the productive code instantiates a logic class, like a calculator, the tests will check the behavior of both classes, mixing the concepts ● Changes in the collaborator's behavior can break also the main class tests, leading to brittle tests 10
  • 11. Loose coupling, dependency injection instead of objects creation ● Example – instantiated collaborator public int averageCustomersAge(){ return new CustomerRepository().customers().stream() .mapToInt(Customer::age) .average().orElse(0d);} ● The unit test should now fake the result of the call: new CustomerRepository().customers(), which requires know how about customer repository collaborators 11
  • 12. Loose coupling, dependency injection instead of objects creation ● Example – injected collaborator class CustomerLogic { private final CustomerRepository repository; CustomerLogic(final CustomerRepository customerRepository){ this.repository = customerRepository;} int averageCustomersAge(){ return repository.customers().stream() .mapToInt(Customer::age) .average().orElse(0d);} } 12
  • 13. Loose coupling, dependency injection instead of objects creation ● Example – injected collaborator, test @Test public void shouldCalculateAverageCorrectly(){ when(repository.customers()).thenReturn( asList( Customer.withAge(20), Customer.withAge(30)) ); final CustomerLogic underTest = new CustomerLogic(repository); assertThat( underTest.averageCustomersAge(), is(25d)); } 13
  • 14. Loose coupling ➢ Replace creation of new objects with dependency injection ➢ Inject all collaborators in the constructor ➢ If forced by the api, create fake constructors visible from the unit tests ➢ Handle the bloated constructors nicely 14
  • 15. Loose coupling, inject collaborators in constructor ● The dependencies are visible in the class API ● It is really easy to write unit tests. When you instantiate the component under test, you just call the constructor, passing mocks, or test doubles as arguments ● You can design immutable classes 15
  • 16. Loose coupling, dependency injection instead of objects creation ● It indicates possible design flaws: is your class still cohesive and follows the single responsibility principle, if it has way too many collaborators? ● Avoid the field injection, even if your dependency injection system allows it 16
  • 17. Loose coupling ➢ Replace creation of new objects with dependency injection ➢ Inject all collaborators in the constructor ➢ If forced by the api, create fake constructors visible from the unit tests ➢ Handle the bloated constructors nicely 17
  • 18. Loose coupling, fake test constructors ● If the API forces a constructor signature that does not allow the injection of the collaborators, do not unit test this main constructor ● Create a package-private constructor, that accepts all collaborators as parameters ● Unit test this package-private constructor 18
  • 19. Loose coupling, fake test constructors ● Example, difficult to test version // The signature is forced by the API, cannot be changed public MessageCenter(final String id){ super(id); this.notificationService = new NotificationService(); this.mailService = new MailService(); } ● This constructor cannot be unit tested in a simple, clean way 19
  • 20. Loose coupling, fake test constructors ● Example, the easy to test version // The signature forced by the API, cannot be changed public MessageCenter(final String id){ this (id, new NotificationService(), new MailService()); } // You can easy test this constructor MessageCenter(final String id, final NotificationService notificationService, final MailService mailService) {...} 20
  • 21. Loose coupling ➢ Replace creation of new objects with dependency injection ➢ Inject all collaborators in the constructor ➢ If forced by the api, create fake constructors visible from the unit tests ➢ Handle the bloated constructors nicely 21
  • 22. Loose coupling, handle bloated constructor ● Injecting all the dependencies in the constructor can lead to a long parameter list ● A long parameter list can signalize lack of cohesion and therefore you should consider refactoring the class in order to split the concerns 22
  • 23. Loose coupling, handle bloated constructor ● If refactoring is not required, search for parameters that belong together: – Group the components into a new class. Use a single instance of the class as constructor argument – Use composition. Inject one object into another and use a single instance of the main class as constructor argument 23
  • 24. What makes your code easy to test Loose coupling No static calls 24 Logic free constructors Compact data creation Clear intent
  • 25. Logic free constructors are easy to test Avoid smart, or hard working constructors
  • 26. Design logic free constructors ● The code in the constructor is run by each test. A “hard working” constructor makes your tests slow ● Avoid any object creation in the constructor, like connections, entity managers, or providers ● Any “new” call in constructor could trigger a pyramid of calls, that will make your tests slow and brittle 26
  • 27. Design logic free constructors ● The constructors should ideally just initialize instance variables with constructor arguments values ● The usage of “init()” blocks, post construct blocks, or static code initializers is cheating and we know it 27
  • 28. What makes your code easy to test Loose coupling No static calls 28 Logic free constructors Compact data creation Clear intent
  • 29. 29 The instance method calls are easy to fake Use them as long as possible, avoid static calls
  • 30. Static calls ➢ Collaborators are not visible in your API ➢ Collaborators behavior can change without notice ➢ Static calls can force you to register transitive dependencies ➢ Singletons are dependencies 30
  • 31. No static calls, collaborators not declared in API ● The collaborators that receive the static call are not declared transparently, in the public API ● The static calls are like secret communication channels to unknown entities ● Replacing the static calls with instance calls on injected collaborators make the API clear 31
  • 32. Static calls ➢ Collaborators are not visible in your API ➢ Collaborators behavior can change without notice ➢ Static calls can force you to register transitive dependencies ➢ Singletons are dependencies 32
  • 33. No static calls, collaborator's behavior changes ● Since not all the mocking frameworks support static calls, you might end up running real static calls and faking some second level dependencies ● If the receiver of a static call delegates to another collaborator, the mock rules will not be triggered ● The tests can fail with no reason (false positives) and are no longer a refactoring safety net 33
  • 34. Static calls ➢ Collaborators are not visible in your API ➢ Collaborators behavior can change without notice ➢ Static calls can force you to register transitive dependencies ➢ Singletons are dependencies 34
  • 35. No static calls, transitive dependencies ● If the tests run real static calls, you might be forced to register in the test also the static collaborators dependencies ● Example: if the collaborator uses a globally defined WebSession object, your test should also register it in the ThreadLocal ● You might be forced to run the test in a suite 35
  • 36. Static calls ➢ Collaborators are not visible in your API ➢ Collaborators behavior can change without notice ➢ Static calls can force you to register transitive dependencies ➢ Singletons are dependencies 36
  • 37. No static calls, singletons ● Singletons are provided over a static factory method call, that can not be mocked. You need to mock the singleton dependencies ● Since the singleton behavior can change without notice, you should treat it as a dependency ● Prefer injecting beans with singleton scope. Their method calls can also be cached 37
  • 38. What makes your code easy to test Loose coupling No static calls 38 Logic free constructors Compact data creation Clear intent
  • 39. 39 The tests need to create data Builders are better than setters
  • 40. Compact data creation ● It is really difficult to create complex test data, if the domain classes expose only setters and allArgsConstructors ● If you control the domain classes, make sure you design them small and cohesive ● Consider providing builders and / or “with”-ers as alternative to setters 40
  • 41. Compact data creation ● Setters mean mutable objects. Use them only if you really need data objects ● The creation of Java beans in the test leads to long set up methods, that are hard to follow and boring to read ● AllArgsConstructor calls force the tests to provide values for all the bean fields, even if irrelevant 41
  • 42. Compact data creation ● The builders can create immutable objects ● The builders let you initialize just the relevant fields ● The builders can also initialize behind the scene fields with default values, avoiding duplicated code in each test method 42
  • 43. Compact data creation ● The builders and “with”-ers calls can be chained, increasing the code readability ● Example - “with”-ers Customer regular = customer() .withName(“name”) .withId(123L) .withSubscription(456L); 43
  • 44. Compact data creation ● Example – builder: Customer company = Customer.companyBuilder() .name(“company A”) .id(1234567L) .taxAddress(someAddress()) .mainOfficeAddress(someOtherAddress()) .build(); Customer private = Customer.privateBuilder() .name(“Joe”) .birthday(“1970-01-01”) .homeAddress(“some address”) .postalAddress(“some other address”) .build(); 44
  • 45. What makes your code easy to test Loose coupling No static calls 45 Logic free constructors Compact data creation Clear intent
  • 46. 46 Write clear code, not smart one The tests and the readers of your code will be thankful
  • 47. Clear intent, no magic ● There is way more time invested in maintenance, than in the original code development ● Other developers will most likely extend your code ● The tests should document the code. The good code is simple and its intent is clear. Avoid smart tricks and hidden functionality 47
  • 48. Clear intent, no magic ● Smell: getter with extra functionality class UserMonitor { private User currentUser; User currentUser(){ if (this.currentUser == null) { this.currentUser = loadUser(); validationService.check(currentUser); outboundService.scan(currentUser); } } } ● A whole jungle is hidden behind the getter call 48
  • 49. Clear intent, no magic ● Smell: return default values if not initialized class User { private final List<Subscription> subscriptions; List<Subscription> subscriptions(){ return subscriptions == null ? trial() : subscriptions;}} ● The test code would check if there is a trial subscription for every user, that has no subscriptions 49
  • 50. Clear intent, no magic ● Smell: add data to match client requirements class ServiceLayerMapper { // The user interface algorithm needs an extra empty product! public List<Product> mapBuyedItems(){ return asList( emptyProduct(), mappedItems(purchasedItems()) ); } ● The test code will check if there is always an item in the basket, if the user does not buy anything 50
  • 51. CREDITS ● Growing Object-oriented software, guided by tests (Steve Freeman, Nat Pryce) ● Stephen Colebourne, Code generating beans in java: https://www.slideshare.net/scolebourne/code-generating-beans-in-java ● Misko Hevery, testability explorer blog: http://misko.hevery.com/code-reviewers-guide/ http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ ● Effective Java, Joshua Bloch ● Elegant objects, Yegor Bugayenko 51
  • 52. CREDITS ● Presentation template by SlidesCarnival ● Photographs by Unsplash ● Diverse device hand photos by Facebook Design Resources ● www.freepik.com photos: – Designed by mrsiraphol / Freepik – Designed by ijeab / Freepik – Designed by Onlyyouqj / Freepik – Designed by ijeab / Freepik – Designed by Dashu83 / Freepik 52
  • 53. Any questions? You can find me at: marian.wamsiedel@gmail.com 53THANKS!