View
4.296
Download
0
Category
Preview:
Citation preview
Testing and Testable code
Pawe Szulchttp://paulszulc.wordpress.compaul.szulc@gmail.com
Testing and testable code
Who am I?
Pawe Szulc
Former Sun Campus Ambassador
Java Developer (currently Wicket+Spring+JPA)
Agile Enthusiast
Blog: http://paulszulc.wordpress.com
E-mail: paul.szulc@gmail.com
Testing and testable code
What are we going to talk about?
Testing and testable code
What are we going to talk about?
Test Driven Development
Testing and testable code
What are we going to talk about?
Test Driven Development
Testing
Testing and testable code
What are we going to talk about?
Test Driven Development
Testing
Testable code
Testing and testable code
What are we going to talk about?
Test Driven Development
Testing
Testable code
So of course, we are going to talk about...
Testing and testable code
What are we going to talk about?
Test Driven Development
Testing
Testable code
So of course, we are going to talk about...
DESIGN
Testing and testable code
What are we going to talk about?
Test Driven Development
Testing
Testable code
So of course, we are going to talk about...
DESIGNcontroversial?
Testing and testable code
The ultimate conference question
Testing and testable code
The ultimate conference question
Testing and testable code
The ultimate conference question
Testing and testable code
The ultimate conference question
Paradox?
Testing and testable code
The ultimate conference question
Paradox?
After-party conclusion
TDD is good because I have large set of tests in my application
I don't use TDD because
Code to complex
Code not maintainable twice more effort
Testing and testable code
The ultimate conference question
Paradox?
After-party conclusion
TDD is good because I have large set of tests in my application
I don't use TDD because
Code to complex
Code not maintainable twice more effort
Paradox? No. Misunderstanding? Yes!
Testing and testable code
Test Driven Development
Testing and testable code
Test Driven Development
Really bad name
Testing and testable code
Test Driven Development
Really bad name
It's not about testing, it's about requirements and design
Testing and testable code
Test Driven Development
Really bad name
It's not about testing, it's about requirements and design
Large tests and relatively high coverage are just positive side effects
Testing and testable code
Test Driven Development
Two pitfalls when doing TDD
TDD Prophet
TDD Architect
Testing and testable code
Test Driven Development
Two pitfalls when doing TDD
TDD Prophet
TDD Architect
Test Driven Development is like sex. If you don't like it, you probably ain't doing it right.
Testing and testable code
Example:
Requirement: create login page
Testing and testable code
Example:
Requirement: create login page
Should log in for correct login and password
Should not login for incorrect login
Should not login for incorrect password
Not logged in user is an 'guest user'
Guest user has login 'Guest'
Testing and testable code
Pitfall #1: TDD Prophet
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Ok, right so definitely what I need for start is ...
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Ok, right so definitely what I need for start is ...
I need User domain class!
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Ok, right so definitely what I need for start is ...
I need User domain class!
User need to have login and password fields
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Ok, right so definitely what I need for start is ...
I need User domain class!
User need to have login and password fields
Getters and setters!
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Ok, right so definitely what I need for start is ...
I need User domain class!
User need to have login and password fields
Getters and setters!
Equals and hashCode methods for equality
Testing and testable code
Pitfall #1: TDD Prophet
Ok, let me see, what I got here...
Should log in for correct login and pas..
Should not login fo...
Ok, right so definitely what I need for start is ...
I need User domain class!
User need to have login and password fields
Getters and setters!
Equals and hashCode methods for equality
and so tests writing begins
Testing and testable code
@Test public void testUserCreation() throws Exception { User user = new User(); }
Testing and testable code
@Test public void testUserHasLoginAndPassword() throws Exception { User user = new User(); user.setLogin("login"); user.setPassword("password");
assertEquals("login", user.getLogin()); assertEquals("password", user.getPassword()); }
Testing and testable code
@Test public void testEqualsMethodValidForSameLogin() throws Exception {
User user1 = new User(); user1.setLogin("login");
User user2 = new User(); user2.setLogin("login");
assertEquals(user1, user2); }
Testing and testable code
@Test public void testEqualsMethodReturnsFalseForDifferentLogin() throws Exception {
User user1 = new User(); user1.setLogin("login");
User user2 = new User(); user2.setLogin("login2");
assertFalse(user1.equals(user2)); }
Testing and testable code
@Test public void testEqualsHashCodeConstract() throws Exception {
User user1 = new User(); user1.setLogin("login"); User user2 = new User(); user2.setLogin("login");
assertTrue(user1.equals(user2)); assertEquals(user1.hashCode(),user2.hashCode());
}
Testing and testable code
public class User { private String login, password; public User() { } public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (!login.equals(user.login)) return false; return true; } public int hashCode() { return login.hashCode(); }}Design you get:
Testing and testable code
Example:
Requirement: create login page
Should log in for correct login and password
Should not login for incorrect login
Should not login for incorrect password
Not logged in user is an 'guest user'
Guest user has login 'Guest'
Testing and testable code
Example:
Requirement: create login page
Should log in for correct login and password
Should not login for incorrect login
Should not login for incorrect password
Not logged in user is an 'guest user'
Guest user has login 'Guest'
Testing and testable code
the test should really looked like this: @Test public void shouldLoginForCorrectLoginAndPassword() throws Exception{ // given String login = "login"; String password = "password"; dao.persist(new User(login,password)); // when User user = service.logIn(login, password); // then assertEquals(login, user.getLogin()); assertEquals(password, user.getPassword()); }
Testing and testable code
public class User { private String login, password; public User(String login, String password) { this.login = login; this.password = password; } public String getLogin() { return login; } public String getPassword() { return password; } }
Design you get:
Testing and testable code
public class User { private String login, password; public User() { } public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (!login.equals(user.login)) return false; return true; } public int hashCode() { return login.hashCode(); }}
public class User { private String login, password; public User(String login, String password) { this.login = login; this.password = password; } public String getLogin() { return login; } public String getPassword() { return password; } }
Testing and testable code
Pitfall #1: TDD Prophet consequences
Code:
You are stuck with huge test base and an implementation that you might never need
Smallest change in your code make a lot of tests fail, even if that change isn't caused be change of requirements
Some of the code might never be used. Ever!
Design
Not focusing on requirements
Created design based on experience only.
Design is complex, not maintainable
Testing and testable code
Test Driven Design is about
Testing and testable code
Test Driven Design is about
Requirements
Implement only what the client wants
Testing and testable code
Test Driven Design is about
Requirements
Implement only what the client wants
Design
Smallest design that does the job right
Testing and testable code
Just because you are writing tests before implementation, does not mean you are using TDD practice.
Testing and testable code
Just because you are writing tests before implementation, does not mean you are using TDD practice.
Symptoms of being TDD Prophet:
Testing getters and setters
Asking questions on Internet like:
Should I test private methods?
Is 75% code coverage good enough?
Testing and testable code
Pitfall #2: TDD Architect
Testing and testable code
Pitfall #2: TDD Architect
Gather all requirements
Testing and testable code
Pitfall #2: TDD Architect
Gather all requirements
Create basic architecture using interfaces
Testing and testable code
Pitfall #2: TDD Architect
Gather all requirements
Create basic architecture using interfaces
Start writing tests while implementing previously designed interfaces
Testing and testable code
Pitfall #2: TDD Architect - consequences
Just complexed variation of TDD Prophet
Testing and testable code
Pitfall #2: TDD Architect - consequences
Just complexed variation of TDD Prophet
Bigger chances that code will do what client wants (requirements)
Will not stand a chance when the requirements change (design)
Testing and testable code
Pitfall #2: TDD Architect - consequences
Just complexed variation of TDD Prophet
Bigger chances that code will do what client wants (requirements)
Will not stand a chance when the requirements change (design)
Again: not a TDD practice!
Testing and testable code
So what is TDD practice?
Testing and testable code
So what is TDD practice the idea:
Add test
Run all tests and see the new one failing
Add some code
Run all tests and see the new one succeeds
Refactor
Testing and testable code
So what is TDD practice the idea enhanced:
Pick up a requirement
Add test
Run all tests and see the new one failing
Add some code
Run all tests and see the new one succeeds
Refactor
Testing and testable code
So what is TDD practice the idea enhanced:
Pick up a requirement
Add test that represents the requirement
Run all tests and see the new one failing
Add some code
Run all tests and see the new one succeeds
Refactor
Testing and testable code
So what is TDD practice the idea enhanced:
Pick up a requirement
Add test that represents the requirement
Run all tests and see the new one failing
Add some code
Run all tests and see the new one succeeds
Refactor whenever design is getting ugly
Testing and testable code
So what is TDD practice the idea enhanced:
Pick up a requirement
Add test that represents the requirement
Run all tests and see the new one failing
Add some code
Run all tests and see the new one succeeds
Refactor whenever design is getting ugly
You start with requirement, you end up with design!
Testing and testable code
Test Driven Development
Really bad name
It's not about testing, it's about requirements and design
Large tests and relatively high coverage are just positive side effects
Testing and testable code
Test Driven Development
Really bad name
Test Driven Design
Requirements Driven Design
It's not about testing, it's about requirements and design
Large tests and relatively high coverage are just positive side effects
Testing and testable code
Test Driven Development
Really bad name
Test Driven Design
Requirements Driven Design
It's not about testing, it's about requirements and design
Tests are simply translation of requirements into code language
Large tests and relatively high coverage are just positive side effects
Testing and testable code
The BIG Problem...
Testing and testable code
The BIG Problem...You still simply ain't gonna use TDD.
Testing and testable code
The BIG Problem...You still simply ain't gonna use TDD. whatever the reasons are.
Testing and testable code
The Big Problem
Test Driven Development is like riding a bike
Misko Hevery,GeeCON2009
Testing and testable code
The Big Problem
Test Driven Development is like riding a bike
Misko Hevery,GeeCON2009How to start riding that bike?
Testing and testable code
The Big Problem
Test Driven Development is like riding a bike
Misko Hevery,GeeCON2009How to start riding that bike?
TDD small app
Testing and testable code
The Big Problem
Test Driven Development is like riding a bike
Misko Hevery,GeeCON2009How to start riding that bike?
TDD small app
Bugs Driven Tests
Testing and testable code
Bugs Driven Tests
Testing and testable code
Bugs Driven Tests
Pick up a bug
Testing and testable code
Bugs Driven Tests
Pick up a bug
Write test that checks whether the bug is fixed
Testing and testable code
Bugs Driven Tests
Pick up a bug
Write test that checks whether th bug is fixed
Test should fail
Testing and testable code
Bugs Driven Tests
Pick up a bug
Write test that checks whether th bug is fixed
Test should fail
Fix the bug
Testing and testable code
Bugs Driven Tests
Pick up a bug
Write test that checks whether th bug is fixed
Test should fail
Fix the bug
Test should succeed
Testing and testable code
Bugs Driven Tests pros
Obvious
You know your bug is fixed when your test passes.
No bugs regression
Testing and testable code
Bugs Driven Tests pros
Obvious
You know your bug is fixed when your test passes.
No bugs regression
Cognitive
You start writing tests. It becomes something natural.
Rule 80:20
20% code tested
80% of importance
Testing and testable code
Bugs Driven Tests cons
I just can't!
I would really like to write test for this implementation. But I just simply don't know how!
Testing and testable code
Bugs Driven Tests cons
I just can't!
I would really like to write test for this implementation. But I just simply don't know how!
Example:
Library the ultimate University example :)
Testing and testable code
Bugs Driven Tests cons
public class Library { private BookSearch bookSearch; public Library() { bookSearch = new BookSearch(); } public boolean addReader(Reader r) { ... }}
Testing and testable code
Bugs Driven Tests cons
public class Library { private BookSearch bookSearch; public Library() { bookSearch = new BookSearch(); } public boolean addReader(Reader r) { ... }}
Testing and testable code
Bugs Driven Tests cons
public class BookSearch { public BookSearch() { DBConnection.init(); }}
Testing and testable code
Bugs Driven Tests cons
Problem, because you write your test AFTER the implementation
Code might be not testable and so writing tests hard or even impossible
Testing and testable code
Testable code
Testing and testable code
Testable code
Misko Hevery (http://misko.hevery.com)
Testing and testable code
Testable code
Misko Hevery (http://misko.hevery.com)
Misko Hevery and gruppies
Testing and testable code
Testable code
Testing and testable code
Testable code
Makes testing light and simple activity
Testing and testable code
Testable code
Makes testing light and simple activity
Promotes good design and good quality code
Testing and testable code
Testable code
Makes testing light and simple activity
Promotes good design and good quality code
Declarative
Testing and testable code
Testable code
Makes testing light and simple activity
Promotes good design and good quality code
Declarative
Easy to read
Testing and testable code
Testable code
Makes testing light and simple activity
Promotes good design and good quality code
Declarative
Easy to read
Easy to maintain
Testing and testable code
Global state
Good or Bad?
Testing and testable code
Global state
int a = new Foo().bar();int b = new Foo().bar();
Does: a == b or a !=b
Testing and testable code
Global state
InsanitynounRepeating the same thing and expecting a different result.
Testing and testable code
Global state
Testing and testable code
Global state
Testing and testable code
Global state
Testing and testable code
Global state
Testing and testable code
Global state root problem: globally accessible state
Example:
Class A and class B
A and B does not know anything about each other
Both states depends on global variable
static int count;
Testing and testable code
Global state root problem: globally accessible state
Why problem?
Developers need to read every single line of code to understand the implementation
Test are not isolated, even if they look like they are
You may not have thought of it this way before, but whenever you use static state, youre creating secret communication channels and not making them clear in the API.
Testing and testable code
Global state root problem: globally accessible state
Why problem?
Every test using global state needs it to start in an expected state, or the test will fail.
Global state often prevents tests from being able to run in parallel
Testing and testable code
Singletons
Good or bad?
Testing and testable code
Singletons
Singletons are global state!
Gang Of Four singletons
Private constructor
Static method instantiating
Testing and testable code
Singletons
Singletons are global state!
Gang Of Four singletons
Private constructor
Static method instantiating
Same situation: class A and B both hold reference to singleton C affect each other state
Testing and testable code
Singletons
Singletons are global state!
Gang Of Four singletons
Private constructor
Static method instantiating
Same situation: class A and B both hold reference to singleton C affect each other state
Only exception: no state (rarely happens)
Testing and testable code
Singletons
Singletons are global state!
Gang Of Four singletons
Private constructor
Static method instantiating
Same situation: class A and B both hold reference to singleton C affect each other state
Only exception: no state (rarely happens)
Tests: methods like reset()
Testing and testable code
Main problem with global states (inclugin singletons)
They are liars
Testing and testable code
Main problem with global states (inclugin singletons)
They are liars
They hide from developers true intentions of the implementation
Testing and testable code
Main problem with global states (inclugin singletons)
They are liars
They hide from developers true intentions of the implementation
Far from clean code that talks
Testing and testable code
Dependency Injection
Good or bad?
Testing and testable code
Dependency Injection
Library example once again
Testing and testable code
Dependency Injection
Library example once again
Common flaw: constructor does real work
creating/initializing collaborators
communicating with other services
logic to set up its own state
Testing and testable code
Dependency Injection
Library example once again
Common flaw: constructor does real work
creating/initializing collaborators
communicating with other services
logic to set up its own state
Why problem?
Inflexible coupled design
Unable to inject test mocks
It force collaboration on you
Object graph
Collaboration graph
Testing and testable code
Dependency Injection
Library example
public class Library { private BookSearch bookSearch; public Library() { this.bookSearch = new BookSearch(); } public boolean addReader(Reader r) { ... }}
Testing and testable code
Dependency Injection
Library example
public class Library { private BookSearch bookSearch; @Inject public Library(BookSearch bookSearch) { this.bookSearch = bookSearch; } public boolean addReader(Reader r) { ... }}
Testing and testable code
Using Dependency Injection
You end up with loosely coupled design
Testing and testable code
Using Dependency Injection
You end up with loosely coupled design
Easy to understand classes
Object graph vs creation graph
Declarative style of programming
Testing and testable code
Using Dependency Injection
You end up with loosely coupled design
Easy to understand classes
Object graph vs creation graph
Declarative style of programming
Tests are easy to write
Testing and testable code
More? Give us more!
I would, simply no time... I think?
http://misko.hevery.com/code-reviewers-guide/
Testing and testable code
Small summery:
Testing and testable code
Small summery:
Just because you write test first, does not mean you are using TDD
Testing and testable code
Small summery:
Just because you write test first, does not mean you are using TDD
TDD is about design and requirements
Testing and testable code
Small summery:
Just because you write test first, does not mean you are using TDD
TDD is about design and requirements
More often you use TDD more addicting it becomes
Testing and testable code
Small summery:
Just because you write test first, does not mean you are using TDD
TDD is about design and requirements
More often you use TDD more addicting it becomes
If used efficiently, you develop your code with good pace, code is readable and maintainable. You rarely hear about regression bugs.
Testing and testable code
Small summery:
Just because you write test first, does not mean you are using TDD
TDD is about design and requirements
More often you use TDD more addicting it becomes
If used efficiently, you develop your code with good pace, code is readable and maintainable. You rarely hear about regression bugs.
Bugs Driven Testing good starting point
Testing and testable code
Small summery:
Just because you write test first, does not mean you are using TDD
TDD is about design and requirements
More often you use TDD more addicting it becomes
If used efficiently, you develop your code with good pace, code is readable and maintainable. You rarely hear about regression bugs.
Bugs Driven Testing good starting point
Testable code: clean code that talks
Testing and testable code
Q&A
Do you know what TDD is?
Yes0.95
No0.05
Do you think TDD is a good practice?Column E
Yes0.75
No0.25
Do you use TDD?Column E
Yes0.05
No0.95
Recommended