SlideShare uma empresa Scribd logo
1 de 62
Baixar para ler offline
TDD and mobile:
some forgotten techniques!
Matteo Vaccari
mvaccari@thoughtworks.com
WHY TEST?
Deliver software faster
Deliver valuable
software faster
Deliver valuable
software faster,
sustainably
WHY TEST?
WHY TEST?
• Tests help me design my code
• Tests check that my code works
the developer perspective
the tester perspective
Some tests are less
useful than others…
Bureaucratic tests
1. Think a line of production code
2. Write a test that proves that the line of code exists
3. Write the line of code
4. .
Useful tests
1. Think a behaviour that I would like to have
2. Write a test that proves that the behaviour exists
3. Experiment ways to pass the test
4. $$$!………… Value !!!
What is TDD?
From Growing Object-Oriented Software by Nat Pryce and Steve Freeman
Why is it difficult to
TDD on Android?
The TDD cycle should be
fast!
Value adding ?
Or waste?
fixing Gradle builds
is waste
and is not fun
How do you tell if an activity is value adding or waste?
Imagine doing that activity all the time… how does it feel?
What would the customer say if you do it all the time?
Programming
Skill
> Fancy
Libraries
Model-View
Separation
Model-View Separation
Model-View Separation
App
(Android)
Core
(Pure Java)
Acceptance
Test
Unit
Test
From Growing Object-Oriented Software by Nat Pryce and Steve Freeman
Unit Doctor Acceptance Tests
public void testInchesToCentimeters() throws Throwab
givenTheUserSelectedConversion("in", "cm");
whenTheUserEnters("2");
thenTheResultIs("2.00 in = 5.08 cm");
}
public void testFahrenheitToCelsius() throws Throwab
givenTheUserSelectedConversion("F", "C");
whenTheUserEnters("50");
thenTheResultIs("50.00 F = 10.00 C");
}
public void testUnknownUnits() throws Throwable {
givenTheUserSelectedConversion("ABC", "XYZ");
thenTheResultIs("I don't know how to convert this"
}
public class UnitConversionAcceptanceTest extends ActivityInstrumentationTestCase2<M
public UnitConversionAcceptanceTest() {
super(MainActivity.class);
}
public void testInchesToCentimeters() throws Throwable {
givenTheUserSelectedConversion("in", "cm");
whenTheUserEnters("2");
thenTheResultIs("2.00 in = 5.08 cm");
}
private void givenTheUserSelectedConversion(String fromUnit, String toUnit) throws
setText(R.id.fromUnit, fromUnit);
setText(R.id.toUnit, toUnit);
}
private void whenTheUserEnters(String inputNumber) throws Throwable {
setText(R.id.inputNumber, inputNumber);
}
private void thenTheResultIs(String expectedResult) {
assertEquals(expectedResult, getField(R.id.result).getText());
}
private void setText(final int id, final String text) throws Throwable {
final TextView field = getField(id);
runTestOnUiThread(new Runnable() {
}
private void givenTheUserSelectedConversion(String fromUnit, String toUnit) throws
setText(R.id.fromUnit, fromUnit);
setText(R.id.toUnit, toUnit);
}
private void whenTheUserEnters(String inputNumber) throws Throwable {
setText(R.id.inputNumber, inputNumber);
}
private void thenTheResultIs(String expectedResult) {
assertEquals(expectedResult, getField(R.id.result).getText());
}
private void setText(final int id, final String text) throws Throwable {
final TextView field = getField(id);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
field.setText(text);
}
});
}
private TextView getField(int id) {
return (TextView) getActivity().findViewById(id);
}
}
The simplest thing
public class MyActivity extends Activity implements View.OnKeyListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
getEditText(R.id.inputNumber).setOnKeyListener(this);
getEditText(R.id.fromUnit).setOnKeyListener(this);
getEditText(R.id.toUnit).setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
String input = getEditText(R.id.inputNumber).getText();
String fromUnit = getEditText(R.id.fromUnit).getText();
String toUnit = getEditText(R.id.toUnit).getText();
getEditText(R.id.result).setText(" Hello! " + input + fromUnit + toUnit);
return false;
}
private EditText getEditText(int id) {
return (EditText) findViewById(id);
}
The simplest thing
public class MyActivity extends Activity implements View.OnKeyListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
getEditText(R.id.inputNumber).setOnKeyListener(this);
getEditText(R.id.fromUnit).setOnKeyListener(this);
getEditText(R.id.toUnit).setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
String input = getEditText(R.id.inputNumber).getText();
String fromUnit = getEditText(R.id.fromUnit).getText();
String toUnit = getEditText(R.id.toUnit).getText();
getEditText(R.id.result).setText(new UnitDoctor().convert(input, fromUnit, toUnit));
return false;
}
private EditText getEditText(int id) {
return (EditText) findViewById(id);
}
Very easy to test
public class UnitDoctorTest {
@Test
public void convertsInchesToCentimeters() {
UnitDoctor unitDoctor = new UnitDoctor();
assertEquals("2.54", unitDoctor.convert("1", "in", "cm"));
}
}
Yes yes… but my app
interacts heavily with
Android widgets!
Presenter-First
public class UnitDoctorTest {
@Rule public JUnitRuleMockery context = new JUnitRuleMockery()
UnitDoctorView view = context.mock(UnitDoctorView.class);
UnitDoctor unitDoctor = new UnitDoctor(view);
@Test
public void convertInchesToCm() throws Exception {
context.checking(new Expectations() {{
allowing(view).inputNumber(); will(returnValue(1.0));
allowing(view).fromUnit(); will(returnValue("in"));
allowing(view).toUnit(); will(returnValue("cm"));
oneOf(view).showResult(2.54);
}});
unitDoctor.convert();
}
What are mocks good for?
Mocking Android APIs?
Discovering interfaces ✅
Discover the “view” interface
public interface UnitDoctorView {
double inputNumber();
String fromUnit();
String toUnit();
void showResult(double result);
}
Presenter-First
public class UnitDoctorTest {
@Rule public JUnitRuleMockery context = new JUnitRuleMockery()
UnitDoctorView view = context.mock(UnitDoctorView.class);
UnitDoctor unitDoctor = new UnitDoctor(view);
@Test
public void convertInchesToCm() throws Exception {
context.checking(new Expectations() {{
allowing(view).inputNumber(); will(returnValue(1.0));
allowing(view).fromUnit(); will(returnValue("in"));
allowing(view).toUnit(); will(returnValue("cm"));
oneOf(view).showResult(2.54);
}});
unitDoctor.convert();
}
Discover the “view” interface
@Test
public void showsConversionNotSupported() throws Exception {
context.checking(new Expectations() {{
allowing(view).inputNumber(); will(returnValue(anyDouble()));
allowing(view).fromUnit(); will(returnValue("XYZ"));
allowing(view).toUnit(); will(returnValue("ABC"));
oneOf(view).showConversionNotSupported();
}});
unitDoctor.convert();
}
Discover the “view” interface
public interface UnitDoctorView {
double inputNumber();
String fromUnit();
String toUnit();
void showResult(double result);
void showConversionNotSupported();
}
Implement the “view”
interface
• In the Activity class
• In an Android View class
• In a new POJO class
Yes, yes, yes… but my
app interacts heavily with
Android APIs!
Acceptance tests
• Single touch. Dragging the finger should produce
a colored trail that fades to nothing
• Two touches. Dragging two fingers should
produce two decaying trails
• Multi-touch dashes. Draw a pattern like

—— —-— —-—

———————————
Start with a spike!
Start with a spike!
public class FingerView extends View {
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
canvas.canvas.drawLine(100, 100, 200, 200, paint);
}
}
More spike!
More spike!
public class MyView extends View {
List<Point> points = new ArrayList<Point>();
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
for (int i=1; i<points.size(); i++) {
Point from = points.get(i-1);
Point to = points.get(i);
canvas.drawLine(from.x, from.y, to.x, to.y, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
points.clear();
points.add(new Point((int) event.getX(), (int) event.getY()));
} else if (action == MotionEvent.ACTION_MOVE) {
points.add(new Point((int) event.getX(), (int) event.getY()));
}
invalidate();
return true;
}
}
FairyFingers
Core
Android
MotionEvent
Android
Canvas
FairyFingersView
onDraw(Canvas) { ... }
onTouchEvent(MotionEvent) { ... }
Android dependent
Pure Java
FairyFingers
Core
Android
MotionEvent
Android
Canvas
FairyFingersView
onDraw(Canvas) { ... }
onTouchEvent(MotionEvent) { ... }
Core
Canvas
Core
MotionEvent
Android dependent
Pure Java
Model-View Separation
App
(Android)
Core
(Pure Java)
Acceptance
Test
Unit
Test
public class FairyFingersCoreTest {
FairyFingersCore core = new FairyFingersCore();
@Test
public void noLinesAtStart() throws Exception {
assertEquals(0, core.lines().size());
}
@Test
public void startOneLine() throws Exception {
core.onTouch(down(10.0f, 100.0f));
assertEquals(1, core.lines().size());
assertEquals("(10.0,100.0)", core.lines(0).toString());
}
@Test
public void oneLineDownMove() throws Exception {
core.onTouch(down(10.0f, 110.0f));
core.onTouch(move(20.0f, 120.0f));
core.onTouch(move(30.0f, 130.0f));
assertEquals("(10.0,110.0)->(20.0,120.0)->(30.0,130.0)", core.lines(0).toString());
}
@Test
public void oneLineDownMoveUp() throws Exception {
core.onTouch(down(10.0f, 100.0f));
core.onTouch(move(20.9f, 120.0f));
TDD!
TDD!
@Override
public boolean onTouchEvent(final MotionEvent event) {
core.onTouch(new CoreMotionEvent() {
@Override
public int getPointerCount() {
return event.getPointerCount();
}
@Override
public int getPointerId(int pointerIndex) {
return event.getPointerId(pointerIndex);
}
@Override
public void getPointerCoords(int pointerIndex, CorePoint outPointerCoords) {
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
event.getPointerCoords(pointerIndex, coords);
outPointerCoords.x = coords.x;
outPointerCoords.y = coords.y;
}
@Override
public int getActionIndex() {
return event.getActionIndex();
}
@Override
public int getAction() {
public interface CoreCanvas {
void drawLine(float startX, float startY, float stopX, float stopY);
}
@Override
protected void onDraw(final Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setStrokeWidth(4);
for (Line line : core.lines()) {
line.drawOn(new CoreCanvas() {
@Override
public void drawLine(float startX, float startY, float stopX, float stopY) {
canvas.drawLine(startX, startY, stopX, stopY, paint);
}
});
}
}
public interface CoreMotionEvent {
int getAction();
int getPointerCount();
int getPointerId(int pointerIndex);
void getPointerCoords(int pointerIndex, CorePoint outPointerCoords);
}
// Constants copied from android.view.MotionEven
static final int ACTION_DOWN = 0;
static final int ACTION_UP = 1;
static final int ACTION_MOVE = 2;
static final int ACTION_CANCEL = 3;
static final int ACTION_POINTER_DOWN = 5;
static final int ACTION_POINTER_UP = 6;
Programming
Skill
> Fancy
Libraries
Value adding ?
Or waste?
Deliver valuable
software faster,
sustainably
References
TDD For Android book (unfinished!) leanpub.com/tddforandroid
Source code for examples: github.com/xpmatteo
These slides are on slideshare.net/xpmatteo
Learn OOP and TDD well:

Growing Object-Oriented Software, Nat Pryce and Steve Freeman

TDD By Example, Kent Beck

Applying UML and Patterns, Craig Larman
Credits
• Carlo Bellettini was my sparring partner for this work
• The motto “Deliver valuable software faster, sustainably” is
my elaboration on Dan North’s “The goal of software
delivery is to minimise the lead time to business impact.
Everything else is detail.” I advise to attend one of Dan’s
seminars. They are illuminating.
• The “Fairy Fingers” idea is from “Ribbons” by Carlo Pescio
(www.aspectroid.com)
• The “gravity test” example is derived from a presentation
by Diego Torres Milano
Questions?
THANK YOU
WE’RE HIRING!

Mais conteúdo relacionado

Mais procurados

Lombok Features
Lombok FeaturesLombok Features
Lombok Features文峰 眭
 
Say Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android DevelopmentSay Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android DevelopmentAdam Magaña
 
React Native One Day
React Native One DayReact Native One Day
React Native One DayTroy Miles
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performanceintelliyole
 
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017Hardik Trivedi
 
Practical tips for building apps with kotlin
Practical tips for building apps with kotlinPractical tips for building apps with kotlin
Practical tips for building apps with kotlinAdit Lal
 
Save time with kotlin in android development
Save time with kotlin in android developmentSave time with kotlin in android development
Save time with kotlin in android developmentAdit Lal
 
Why Java Sucks and C# Rocks (Final)
Why Java Sucks and C# Rocks (Final)Why Java Sucks and C# Rocks (Final)
Why Java Sucks and C# Rocks (Final)jeffz
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Arnaud Giuliani
 
ADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersBartosz Kosarzycki
 
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)Andrés Viedma Peláez
 
Geecon - Improve your Android-fu with Kotlin
Geecon - Improve your Android-fu with KotlinGeecon - Improve your Android-fu with Kotlin
Geecon - Improve your Android-fu with KotlinNicolas Fränkel
 
Getting Started With Kotlin
Getting Started With KotlinGetting Started With Kotlin
Getting Started With KotlinGaurav sharma
 
Android Architecture Components with Kotlin
Android Architecture Components with KotlinAndroid Architecture Components with Kotlin
Android Architecture Components with KotlinAdit Lal
 
Introduction to Programming Bots
Introduction to Programming BotsIntroduction to Programming Bots
Introduction to Programming BotsDmitri Nesteruk
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsBartosz Kosarzycki
 
Swift and Kotlin Presentation
Swift and Kotlin PresentationSwift and Kotlin Presentation
Swift and Kotlin PresentationAndrzej Sitek
 
A Deeper look into Javascript Basics
A Deeper look into Javascript BasicsA Deeper look into Javascript Basics
A Deeper look into Javascript BasicsMindfire Solutions
 

Mais procurados (20)

Lombok Features
Lombok FeaturesLombok Features
Lombok Features
 
Say Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android DevelopmentSay Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android Development
 
Kotlin - Better Java
Kotlin - Better JavaKotlin - Better Java
Kotlin - Better Java
 
React Native One Day
React Native One DayReact Native One Day
React Native One Day
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performance
 
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017Introduction to kotlin for android app development   gdg ahmedabad dev fest 2017
Introduction to kotlin for android app development gdg ahmedabad dev fest 2017
 
Practical tips for building apps with kotlin
Practical tips for building apps with kotlinPractical tips for building apps with kotlin
Practical tips for building apps with kotlin
 
Save time with kotlin in android development
Save time with kotlin in android developmentSave time with kotlin in android development
Save time with kotlin in android development
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Why Java Sucks and C# Rocks (Final)
Why Java Sucks and C# Rocks (Final)Why Java Sucks and C# Rocks (Final)
Why Java Sucks and C# Rocks (Final)
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
 
ADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developers
 
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
Poniendo Kotlin en producción a palos (Kotlin in production, the hard way)
 
Geecon - Improve your Android-fu with Kotlin
Geecon - Improve your Android-fu with KotlinGeecon - Improve your Android-fu with Kotlin
Geecon - Improve your Android-fu with Kotlin
 
Getting Started With Kotlin
Getting Started With KotlinGetting Started With Kotlin
Getting Started With Kotlin
 
Android Architecture Components with Kotlin
Android Architecture Components with KotlinAndroid Architecture Components with Kotlin
Android Architecture Components with Kotlin
 
Introduction to Programming Bots
Introduction to Programming BotsIntroduction to Programming Bots
Introduction to Programming Bots
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
 
Swift and Kotlin Presentation
Swift and Kotlin PresentationSwift and Kotlin Presentation
Swift and Kotlin Presentation
 
A Deeper look into Javascript Basics
A Deeper look into Javascript BasicsA Deeper look into Javascript Basics
A Deeper look into Javascript Basics
 

Semelhante a TDD and mobile development: some forgotten techniques, illustrated with Android

Matteo Vaccari - TDD per Android | Codemotion Milan 2015
Matteo Vaccari - TDD per Android | Codemotion Milan 2015Matteo Vaccari - TDD per Android | Codemotion Milan 2015
Matteo Vaccari - TDD per Android | Codemotion Milan 2015Codemotion
 
TDD by Controlling Dependencies
TDD by Controlling DependenciesTDD by Controlling Dependencies
TDD by Controlling DependenciesJorge Ortiz
 
Who killed object oriented design?
Who killed object oriented design?Who killed object oriented design?
Who killed object oriented design?Amir Barylko
 
Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*Intel® Software
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?PVS-Studio
 
Why the Dark Side should use Swift and a SOLID Architecture
Why the Dark Side should use Swift and a SOLID ArchitectureWhy the Dark Side should use Swift and a SOLID Architecture
Why the Dark Side should use Swift and a SOLID ArchitectureJorge Ortiz
 
What's new in c# 8.0
What's new in c# 8.0What's new in c# 8.0
What's new in c# 8.0Moaid Hathot
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2Leonid Maslov
 
Reflection in Go
Reflection in GoReflection in Go
Reflection in Gostrikr .
 
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
JDD 2016 - Sebastian Malaca - You Dont Need Unit TestsJDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
JDD 2016 - Sebastian Malaca - You Dont Need Unit TestsPROIDEA
 
Android testing
Android testingAndroid testing
Android testingSean Tsai
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimizedWoody Pewitt
 
Intro to object oriented programming
Intro to object oriented programmingIntro to object oriented programming
Intro to object oriented programmingDavid Giard
 
The real beginner's guide to android testing
The real beginner's guide to android testingThe real beginner's guide to android testing
The real beginner's guide to android testingEric (Trung Dung) Nguyen
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607Kevin Hazzard
 
Droidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offlineDroidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offlineJavier de Pedro López
 

Semelhante a TDD and mobile development: some forgotten techniques, illustrated with Android (20)

Matteo Vaccari - TDD per Android | Codemotion Milan 2015
Matteo Vaccari - TDD per Android | Codemotion Milan 2015Matteo Vaccari - TDD per Android | Codemotion Milan 2015
Matteo Vaccari - TDD per Android | Codemotion Milan 2015
 
TDD by Controlling Dependencies
TDD by Controlling DependenciesTDD by Controlling Dependencies
TDD by Controlling Dependencies
 
Who killed object oriented design?
Who killed object oriented design?Who killed object oriented design?
Who killed object oriented design?
 
Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?
 
Why the Dark Side should use Swift and a SOLID Architecture
Why the Dark Side should use Swift and a SOLID ArchitectureWhy the Dark Side should use Swift and a SOLID Architecture
Why the Dark Side should use Swift and a SOLID Architecture
 
What's new in c# 8.0
What's new in c# 8.0What's new in c# 8.0
What's new in c# 8.0
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
 
Reflection in Go
Reflection in GoReflection in Go
Reflection in Go
 
Object-oriented Basics
Object-oriented BasicsObject-oriented Basics
Object-oriented Basics
 
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
JDD 2016 - Sebastian Malaca - You Dont Need Unit TestsJDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
 
Devoxx 2012 (v2)
Devoxx 2012 (v2)Devoxx 2012 (v2)
Devoxx 2012 (v2)
 
Android testing
Android testingAndroid testing
Android testing
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
mobl
moblmobl
mobl
 
Intro to object oriented programming
Intro to object oriented programmingIntro to object oriented programming
Intro to object oriented programming
 
The real beginner's guide to android testing
The real beginner's guide to android testingThe real beginner's guide to android testing
The real beginner's guide to android testing
 
Effective Object Oriented Design in Cpp
Effective Object Oriented Design in CppEffective Object Oriented Design in Cpp
Effective Object Oriented Design in Cpp
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
 
Droidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offlineDroidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offline
 

Mais de Codemotion

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Codemotion
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyCodemotion
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaCodemotion
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserCodemotion
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Codemotion
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Codemotion
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Codemotion
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 - Codemotion
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Codemotion
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Codemotion
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Codemotion
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Codemotion
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Codemotion
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Codemotion
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Codemotion
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...Codemotion
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Codemotion
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Codemotion
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Codemotion
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Codemotion
 

Mais de Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Último

BDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort ServiceBDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort ServiceDelhi Call girls
 
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual serviceCALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual serviceanilsa9823
 
FULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCR
FULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCRFULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCR
FULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCRnishacall1
 
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost LoverPowerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost LoverPsychicRuben LoveSpells
 
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,Pooja Nehwal
 
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun serviceCALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun serviceanilsa9823
 
9892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x79892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x7Pooja Nehwal
 

Último (7)

BDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort ServiceBDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 71 Noida Escorts >༒8448380779 Escort Service
 
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual serviceCALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
 
FULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCR
FULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCRFULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCR
FULL ENJOY - 9999218229 Call Girls in {Mahipalpur}| Delhi NCR
 
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost LoverPowerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
 
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
 
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun serviceCALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
 
9892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x79892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x7
 

TDD and mobile development: some forgotten techniques, illustrated with Android

  • 1. TDD and mobile: some forgotten techniques! Matteo Vaccari mvaccari@thoughtworks.com
  • 7. WHY TEST? • Tests help me design my code • Tests check that my code works the developer perspective the tester perspective
  • 8. Some tests are less useful than others…
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14. Bureaucratic tests 1. Think a line of production code 2. Write a test that proves that the line of code exists 3. Write the line of code 4. .
  • 15. Useful tests 1. Think a behaviour that I would like to have 2. Write a test that proves that the behaviour exists 3. Experiment ways to pass the test 4. $$$!………… Value !!!
  • 17. From Growing Object-Oriented Software by Nat Pryce and Steve Freeman
  • 18. Why is it difficult to TDD on Android?
  • 19. The TDD cycle should be fast!
  • 20.
  • 22. fixing Gradle builds is waste and is not fun How do you tell if an activity is value adding or waste? Imagine doing that activity all the time… how does it feel? What would the customer say if you do it all the time?
  • 27. From Growing Object-Oriented Software by Nat Pryce and Steve Freeman
  • 28. Unit Doctor Acceptance Tests public void testInchesToCentimeters() throws Throwab givenTheUserSelectedConversion("in", "cm"); whenTheUserEnters("2"); thenTheResultIs("2.00 in = 5.08 cm"); } public void testFahrenheitToCelsius() throws Throwab givenTheUserSelectedConversion("F", "C"); whenTheUserEnters("50"); thenTheResultIs("50.00 F = 10.00 C"); } public void testUnknownUnits() throws Throwable { givenTheUserSelectedConversion("ABC", "XYZ"); thenTheResultIs("I don't know how to convert this" }
  • 29. public class UnitConversionAcceptanceTest extends ActivityInstrumentationTestCase2<M public UnitConversionAcceptanceTest() { super(MainActivity.class); } public void testInchesToCentimeters() throws Throwable { givenTheUserSelectedConversion("in", "cm"); whenTheUserEnters("2"); thenTheResultIs("2.00 in = 5.08 cm"); } private void givenTheUserSelectedConversion(String fromUnit, String toUnit) throws setText(R.id.fromUnit, fromUnit); setText(R.id.toUnit, toUnit); } private void whenTheUserEnters(String inputNumber) throws Throwable { setText(R.id.inputNumber, inputNumber); } private void thenTheResultIs(String expectedResult) { assertEquals(expectedResult, getField(R.id.result).getText()); } private void setText(final int id, final String text) throws Throwable { final TextView field = getField(id); runTestOnUiThread(new Runnable() {
  • 30. } private void givenTheUserSelectedConversion(String fromUnit, String toUnit) throws setText(R.id.fromUnit, fromUnit); setText(R.id.toUnit, toUnit); } private void whenTheUserEnters(String inputNumber) throws Throwable { setText(R.id.inputNumber, inputNumber); } private void thenTheResultIs(String expectedResult) { assertEquals(expectedResult, getField(R.id.result).getText()); } private void setText(final int id, final String text) throws Throwable { final TextView field = getField(id); runTestOnUiThread(new Runnable() { @Override public void run() { field.setText(text); } }); } private TextView getField(int id) { return (TextView) getActivity().findViewById(id); } }
  • 31. The simplest thing public class MyActivity extends Activity implements View.OnKeyListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); getEditText(R.id.inputNumber).setOnKeyListener(this); getEditText(R.id.fromUnit).setOnKeyListener(this); getEditText(R.id.toUnit).setOnKeyListener(this); } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { String input = getEditText(R.id.inputNumber).getText(); String fromUnit = getEditText(R.id.fromUnit).getText(); String toUnit = getEditText(R.id.toUnit).getText(); getEditText(R.id.result).setText(" Hello! " + input + fromUnit + toUnit); return false; } private EditText getEditText(int id) { return (EditText) findViewById(id); }
  • 32. The simplest thing public class MyActivity extends Activity implements View.OnKeyListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); getEditText(R.id.inputNumber).setOnKeyListener(this); getEditText(R.id.fromUnit).setOnKeyListener(this); getEditText(R.id.toUnit).setOnKeyListener(this); } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { String input = getEditText(R.id.inputNumber).getText(); String fromUnit = getEditText(R.id.fromUnit).getText(); String toUnit = getEditText(R.id.toUnit).getText(); getEditText(R.id.result).setText(new UnitDoctor().convert(input, fromUnit, toUnit)); return false; } private EditText getEditText(int id) { return (EditText) findViewById(id); }
  • 33. Very easy to test public class UnitDoctorTest { @Test public void convertsInchesToCentimeters() { UnitDoctor unitDoctor = new UnitDoctor(); assertEquals("2.54", unitDoctor.convert("1", "in", "cm")); } }
  • 34. Yes yes… but my app interacts heavily with Android widgets!
  • 35. Presenter-First public class UnitDoctorTest { @Rule public JUnitRuleMockery context = new JUnitRuleMockery() UnitDoctorView view = context.mock(UnitDoctorView.class); UnitDoctor unitDoctor = new UnitDoctor(view); @Test public void convertInchesToCm() throws Exception { context.checking(new Expectations() {{ allowing(view).inputNumber(); will(returnValue(1.0)); allowing(view).fromUnit(); will(returnValue("in")); allowing(view).toUnit(); will(returnValue("cm")); oneOf(view).showResult(2.54); }}); unitDoctor.convert(); }
  • 36. What are mocks good for? Mocking Android APIs? Discovering interfaces ✅
  • 37. Discover the “view” interface public interface UnitDoctorView { double inputNumber(); String fromUnit(); String toUnit(); void showResult(double result); }
  • 38. Presenter-First public class UnitDoctorTest { @Rule public JUnitRuleMockery context = new JUnitRuleMockery() UnitDoctorView view = context.mock(UnitDoctorView.class); UnitDoctor unitDoctor = new UnitDoctor(view); @Test public void convertInchesToCm() throws Exception { context.checking(new Expectations() {{ allowing(view).inputNumber(); will(returnValue(1.0)); allowing(view).fromUnit(); will(returnValue("in")); allowing(view).toUnit(); will(returnValue("cm")); oneOf(view).showResult(2.54); }}); unitDoctor.convert(); }
  • 39. Discover the “view” interface @Test public void showsConversionNotSupported() throws Exception { context.checking(new Expectations() {{ allowing(view).inputNumber(); will(returnValue(anyDouble())); allowing(view).fromUnit(); will(returnValue("XYZ")); allowing(view).toUnit(); will(returnValue("ABC")); oneOf(view).showConversionNotSupported(); }}); unitDoctor.convert(); }
  • 40. Discover the “view” interface public interface UnitDoctorView { double inputNumber(); String fromUnit(); String toUnit(); void showResult(double result); void showConversionNotSupported(); }
  • 41. Implement the “view” interface • In the Activity class • In an Android View class • In a new POJO class
  • 42. Yes, yes, yes… but my app interacts heavily with Android APIs!
  • 43.
  • 44. Acceptance tests • Single touch. Dragging the finger should produce a colored trail that fades to nothing • Two touches. Dragging two fingers should produce two decaying trails • Multi-touch dashes. Draw a pattern like
 —— —-— —-—
 ———————————
  • 45. Start with a spike!
  • 46. Start with a spike! public class FingerView extends View { @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.BLUE); paint.setStrokeWidth(3); paint.setStyle(Paint.Style.STROKE); canvas.canvas.drawLine(100, 100, 200, 200, paint); } }
  • 48. More spike! public class MyView extends View { List<Point> points = new ArrayList<Point>(); @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.BLUE); paint.setStrokeWidth(3); for (int i=1; i<points.size(); i++) { Point from = points.get(i-1); Point to = points.get(i); canvas.drawLine(from.x, from.y, to.x, to.y, paint); } } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { points.clear(); points.add(new Point((int) event.getX(), (int) event.getY())); } else if (action == MotionEvent.ACTION_MOVE) { points.add(new Point((int) event.getX(), (int) event.getY())); } invalidate(); return true; } }
  • 49. FairyFingers Core Android MotionEvent Android Canvas FairyFingersView onDraw(Canvas) { ... } onTouchEvent(MotionEvent) { ... } Android dependent Pure Java
  • 50. FairyFingers Core Android MotionEvent Android Canvas FairyFingersView onDraw(Canvas) { ... } onTouchEvent(MotionEvent) { ... } Core Canvas Core MotionEvent Android dependent Pure Java
  • 52. public class FairyFingersCoreTest { FairyFingersCore core = new FairyFingersCore(); @Test public void noLinesAtStart() throws Exception { assertEquals(0, core.lines().size()); } @Test public void startOneLine() throws Exception { core.onTouch(down(10.0f, 100.0f)); assertEquals(1, core.lines().size()); assertEquals("(10.0,100.0)", core.lines(0).toString()); } @Test public void oneLineDownMove() throws Exception { core.onTouch(down(10.0f, 110.0f)); core.onTouch(move(20.0f, 120.0f)); core.onTouch(move(30.0f, 130.0f)); assertEquals("(10.0,110.0)->(20.0,120.0)->(30.0,130.0)", core.lines(0).toString()); } @Test public void oneLineDownMoveUp() throws Exception { core.onTouch(down(10.0f, 100.0f)); core.onTouch(move(20.9f, 120.0f)); TDD!
  • 53. TDD!
  • 54. @Override public boolean onTouchEvent(final MotionEvent event) { core.onTouch(new CoreMotionEvent() { @Override public int getPointerCount() { return event.getPointerCount(); } @Override public int getPointerId(int pointerIndex) { return event.getPointerId(pointerIndex); } @Override public void getPointerCoords(int pointerIndex, CorePoint outPointerCoords) { MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords(); event.getPointerCoords(pointerIndex, coords); outPointerCoords.x = coords.x; outPointerCoords.y = coords.y; } @Override public int getActionIndex() { return event.getActionIndex(); } @Override public int getAction() {
  • 55. public interface CoreCanvas { void drawLine(float startX, float startY, float stopX, float stopY); } @Override protected void onDraw(final Canvas canvas) { paint.setColor(Color.BLUE); paint.setStrokeWidth(4); for (Line line : core.lines()) { line.drawOn(new CoreCanvas() { @Override public void drawLine(float startX, float startY, float stopX, float stopY) { canvas.drawLine(startX, startY, stopX, stopY, paint); } }); } }
  • 56. public interface CoreMotionEvent { int getAction(); int getPointerCount(); int getPointerId(int pointerIndex); void getPointerCoords(int pointerIndex, CorePoint outPointerCoords); } // Constants copied from android.view.MotionEven static final int ACTION_DOWN = 0; static final int ACTION_UP = 1; static final int ACTION_MOVE = 2; static final int ACTION_CANCEL = 3; static final int ACTION_POINTER_DOWN = 5; static final int ACTION_POINTER_UP = 6;
  • 60. References TDD For Android book (unfinished!) leanpub.com/tddforandroid Source code for examples: github.com/xpmatteo These slides are on slideshare.net/xpmatteo Learn OOP and TDD well:
 Growing Object-Oriented Software, Nat Pryce and Steve Freeman
 TDD By Example, Kent Beck
 Applying UML and Patterns, Craig Larman
  • 61. Credits • Carlo Bellettini was my sparring partner for this work • The motto “Deliver valuable software faster, sustainably” is my elaboration on Dan North’s “The goal of software delivery is to minimise the lead time to business impact. Everything else is detail.” I advise to attend one of Dan’s seminars. They are illuminating. • The “Fairy Fingers” idea is from “Ribbons” by Carlo Pescio (www.aspectroid.com) • The “gravity test” example is derived from a presentation by Diego Torres Milano