0% found this document useful (0 votes)
46 views

Crafting Code: @sandromancuso @codurance

This document provides an agenda and information for a coding workshop focused on test-driven development (TDD). The workshop covers TDD lifecycles and naming conventions, test-driving algorithms, expressing business rules, mocking, and more. Attendees are instructed to have certain tools installed and be prepared to write and run failing tests. The document provides examples and demonstrations of TDD techniques.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views

Crafting Code: @sandromancuso @codurance

This document provides an agenda and information for a coding workshop focused on test-driven development (TDD). The workshop covers TDD lifecycles and naming conventions, test-driving algorithms, expressing business rules, mocking, and more. Attendees are instructed to have certain tools installed and be prepared to write and run failing tests. The document provides examples and demonstrations of TDD techniques.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51

Crafting Code

[email protected]
@sandromancuso
@codurance h/p://codurance.com
Introductions
Who are you?
Which languages do you use?
What’s your experience with TDD?
Why this course?
Forget what you know…
… but just for today

There is no silver bullet when it comes to software.


Agenda
Day 1
•  Introduction to TDD
•  TDD Lifecycle and Naming
•  Test-Driving algorithms
•  Expressing business rules
•  Mocking
Day 2
•  Expressive Tests with Builders
•  Outside-In TDD with Acceptance Tests
•  Testing and Refactoring Legacy Code
Before we start…

Make sure you can do the following:


-  Start a new project
-  Write and run a failing test
assertThat(true, is(false));

Also, make sure you have the following installed:


-  Mocking framework
-  Maven (optional)
-  Git (optional but recommended)

http://codingboard.org/boards/craftingcode
Specify what you want
your code to do.
(failing test)

Red

Refactor Green

Clean your code and test. Create just enough


Remove duplication. code to satisfy the
(make it better) desired behaviour.
(make it work)
Naming convention
Express what the class
should be able to do.

public class MyClassShould {


Reads as a
@Test public void full sentence

do_something_interesting() {
Start with
a verb. }

Tests should clearly specify the behaviour of the class under test.
Avoid technical terms.
Test method structure
public class BankAccountShould{

@Test public void


have_balance_of_zero_when_created() {
BankAccount bankAccount = new BankAccount();

assertThat(bankAccount.balance(), is(0));
}

@Test public void


have_the_balance_increased_after_a_deposit() {
given BankAccount bankAccount = new BankAccount();

when bankAccount.deposit(10);

then assertThat(bankAccount.balance(), is(10));


}

}
Test creation order Step 1: Name the class

public class BankAccountShould{


Step 2: Name the method
@Test public void
have_balance_increased_after_a_deposit() { Step 5: Setup

given BankAccount bankAccount = new BankAccount();

when bankAccount.deposit(10); Step 4: Trigger the


code
then assertThat(bankAccount.balance(), is(10));

}
Step 3: Define what you are testing
}

ProducDon code should be created from the tests.


Bad naming used on tests

BankAccount testee = new BankAccount();


BankAccount sut = new BankAccount();
BankAccount ba = new BankAccount();

test_deposit_works() {…}
test_deposit_works_correctly() {…}
test_deposit() {…}
check_balance_after_deposit() {…}
Bad naming used on tests

BankAccount testee = new BankAccount();


BankAccount sut = new BankAccount();
BankAccount ba = new BankAccount();

If it is a bank account,
call it “bankAccount”

test_deposit_works() {…}
test_deposit_works_correctly() {…}
test_deposit() {…}
check_balance_after_deposit() {…}
Test methods should
indicate the expected
behaviour

increase_the_balance_after_a_deposit()
Tip for professional TDDers: Split your screen

public class MyClassShould { public class MyClass {

@Test public void @Test public void


do_something_useful() { some_behaviour() {
} }

} }
Don’t rush.
Write code you are proud of.
E.1 – TDD lifecycle & naming
 
Objective
- Introduce naming convention
- Create production code from test
- Start from assertion
- Tip for deciding the first test to write: The simplest possible.
 
Problem description: Stack
 
Implement a Stack class with the following public methods:
 
+ void push(Object object)
+ Object pop()
 
Stack should throw an exception if popped when empty.

Stack demo
E.2 – Test-Driving Algorithms
 
Objective
- Grow an algorithm bit by bit
- Delay treating exceptions (in this case, because they are more complex)
- Intentionally cause duplication
- Focus on simple structures first
 

Problem description: Roman Numerals Converter Examples


  1 - I
Implement a Roman numeral converter. The 5 - V
code must be able to take decimals up to 3999 10 - X
and convert to their roman equivalent. 50 - L
100 - C
500 - D
1000 - M
2499 - MMCDXCIX
3949 - MMMCMXLIX

Transformation Priority Premise - TPP

1.  ({}–>nil) no code at all->code that employs nil


2.  (nil->constant)
3.  (constant->constant+) a simple constant to a more complex constant
4.  (constant->scalar) replacing a constant with a variable or an argument
5.  (statement->statements) adding more unconditional statements.
6.  (unconditional->if) splitting the execution path
7.  (scalar->array)
8.  (array->container)
9.  (statement->recursion)
10. (if->while)
11. (expression->function) replacing an expression with a function or
algorithm
12. (variable->assignment) replacing the value of a variable.
Roman Numerals demo
E.3 – Expressing Business Rules
 
Objective
- Clearly express business rules and domain.
- It’s OK to write a passing test if it express a valid
business rule.

Problem description: Leap Year

All the following rules must be saDsfied:
- Is leap year if divisible by 400
- Is NOT leap year if divisible by 100 but not by 400
- Is leap year is divisible by 4

Leap Year demo
Outside-In TDD: Mocking
B C

UT UT
UT
B C
B C

D UT

D
E.4 – Mocking

Problem descrip4on: Payment service

Given a user wants to buy her selected items
When she submits her payment details
Then we should process her payment

Acceptance criteria:
- If the user is not valid, an excepDon should be thrown.
- Payment should be sent to the payment gateway.

Create a class with the following signature:

public class PaymentService {


public void processPayment(User user,
PaymentDetails paymentDetails) {
// your code goes here
}
}

End of Day 1
Agenda
Day 1
•  Introduction to TDD
•  TDD Lifecycle and Naming
•  Test-Driving algorithms
•  Expressing business rules
•  Mocking
Day 2
•  Expressive Tests with Builders
•  Outside-In TDD with Acceptance Tests
•  Testing and Refactoring Legacy Code
E.5 – Expressive Tests with Builders

Objec4ve:
- Write expressive tests
- Remove duplicaDon from tests
- Easily create setup data for tests

Problem descrip4on: Calculate an order total price

An order total price should be equals the sum of its order items totals.

Order structure:

Order Item Product



+total() -quanDty +price()
+total()
Outside-In TDD: Mocking
AT
B’ C
A

B’’
DB

UT UT
UT
B’ C
B’’ C A

B’’ IT

B’’ IMDB
E.6 – Outside-In TDD with Acceptance Tests

Objec4ve:
Learn and pracDce the double loop of TDD
Test applicaDon from outside, according to side effect

Problem descrip4on: Bank kata

Create a simple bank applicaDon with the following features:

- Deposit into Account
- Withdraw from an Account
- Print a bank statement to the console.

Acceptance criteria
Statement should have the following the format:
DATE | AMOUNT | BALANCE
10/04/2014 | 500.00 | 1400.00
02/04/2014 | -100.00 | 900.00
01/04/2014 | 1000.00 | 1000.00

Note: Start with an acceptance test
Account Service

public class AccountService {

public void deposit(int amount);

public void withdraw(int amount);

public void printStatement();

}
E.6 – Outside-In TDD with Acceptance Tests

Proposed acceptance test star4ng point;

@RunWith(MockitoJUntiRunner.class)
public class PrintStatementFeature {

@Mock Console console;

@Test public void


print_statement_containing_transactions_in_reverse_chronological_order() {
AccountService accountService = new AccountService();

accountService.deposit(1000);
accountService.withdraw(100);
accountService.deposit(500);

accountService.printStatement();

InOrder inOrder = inOrder(console);


inOrder.verify(console).printLine("DATE | AMOUNT | BALANCE");
inOrder.verify(console).printLine("10/04/2014 | 500.00 | 1400.00");
inOrder.verify(console).printLine("02/04/2014 | -100.00 | 900.00");
inOrder.verify(console).printLine("01/04/2014 | 1000.00 | 1000.00");
}
}

Legacy Code
Tight Coupling, Low Cohesion,
Feature Envy, Anaemic Domain,
and SRP violation
Exercise
Testing and Refactoring Legacy Code

https://github.com/sandromancuso/trip-service-kata/
What does this code do?
Business Requirements
Imagine a social networking website for
travellers

•  You need to be logged in to see the content
•  You need to be a friend to see someone else’s
trips
Legacy Code Rules
•  You cannot change producDon code if not
covered by tests
–  Just automated refactoring (via IDE) is allowed, in
case it is needed for wriDng a test
Working with Legacy Code Tips

Start refactoring from


deepest to shallowest
branch

Start tes4ng from
shallowest to
deepest branch

Trip Service - Problems

<<Singleton>>
UserSession
+getInstance() : UserSession
+getLoggedUser() : User
TripService
+findTripsByUser(User) : List<Trip>

TripDAO
+findTripsByUser(User) : List<Trip>
Have fun!!!


https://github.com/sandromancuso/trip-service-kata/


Trip Service Kata Tips
You will need the following three tests

•  validate_logged_in_user // throws UserNotLoggedInException
•  does_not_return_any_trips_when_users_are_not_friends
•  return_trips_when_users_are_friends

TIPS

•  Create Seams to isolate dependencies
•  When refactoring, ask yourself if the behaviour belongs to the TripService
•  There are design issues that must be fixed. Dependencies should be injected.
•  As you fix the design, tests become simpler
DEMO
What did we cover
Day 1
•  Introduction to TDD
•  TDD Lifecycle and Naming
•  Test-Driving algorithms
•  Expressing business rules
•  Mocking
Day 2
•  Expressive Tests with Builders
•  Outside-In TDD with Acceptance Tests
•  Testing and Refactoring Legacy Code
Summary of the last 2 days

What did you learn?


Retrospective
Thank you
[email protected]
@sandromancuso

h/p://codurance.com

You might also like