Tomasz Polanski - Droidcon Berlin 2016

41
TESTING Tomek Polanski tpolansk WHY? WHEN? HOW?

Transcript of Tomasz Polanski - Droidcon Berlin 2016

Page 1: Tomasz Polanski - Droidcon Berlin 2016

TESTING

Tomek Polanskitpolansk

WHY?WHEN?HOW?

Page 2: Tomasz Polanski - Droidcon Berlin 2016

“Too much time pressure with making visible changes.

Customer doesn't appreciate tests enough.”

Page 3: Tomasz Polanski - Droidcon Berlin 2016

“To make iterations as fast as possible I would not use tests for

prototypes or early MVPs.”

Page 4: Tomasz Polanski - Droidcon Berlin 2016

“Specs are too volatile, tests would just need to be updated

constantly.”

Page 5: Tomasz Polanski - Droidcon Berlin 2016

“Writing tests is hard, they might be difficult to understand.”

Page 6: Tomasz Polanski - Droidcon Berlin 2016

“Nobody else in the project uses them.

They weren't done or were broken when I got involved.”

Page 7: Tomasz Polanski - Droidcon Berlin 2016

Time and budget“Too much time

pressure with making visible changes”

Page 8: Tomasz Polanski - Droidcon Berlin 2016

Instant changes Return on investment

vs

Page 9: Tomasz Polanski - Droidcon Berlin 2016

Speed

“Not for prototypes or early MVPs”

Page 10: Tomasz Polanski - Droidcon Berlin 2016

Time

Prog

ress

without tests

with tests

Page 11: Tomasz Polanski - Droidcon Berlin 2016

Prototype

Page 12: Tomasz Polanski - Droidcon Berlin 2016

Minimum Viable Product

Lovable

by Henrik Kniberg

Page 13: Tomasz Polanski - Droidcon Berlin 2016

Constant ChangeThe

“Specs are too volatile”

Page 14: Tomasz Polanski - Droidcon Berlin 2016

Programming is hard

https://deeguns.files.wordpress.com/2013/07/computerman.jpg

Page 15: Tomasz Polanski - Droidcon Berlin 2016

urbanattitude.fr/wp-content/uploads/2015/03/BER_08.jpg

Page 16: Tomasz Polanski - Droidcon Berlin 2016

Architecture

“Tests are hard and difficult to understand”

Page 17: Tomasz Polanski - Droidcon Berlin 2016

Maintenance

“Missing/broken tests”

Page 18: Tomasz Polanski - Droidcon Berlin 2016

What should unit tests look like?

Page 19: Tomasz Polanski - Droidcon Berlin 2016

Fast

Page 20: Tomasz Polanski - Droidcon Berlin 2016

Reliable

Page 21: Tomasz Polanski - Droidcon Berlin 2016

Simple to understand@Testpublic void get_whenElementExists() { List<String> list = Collections.singletonList(DEFAULT);

assertThat(get(list, 0)).isEqualTo(DEFAULT);}

@Testpublic void get_whenIndexTooBig_returnNull() { List<String> list = Collections.singletonList(DEFAULT);

assertThat(get(list, 1)).isNull();}

@Testpublic void get_whenIndexTooSmall_returnNull() { List<String> list = Collections.singletonList(DEFAULT);

assertThat(get(list, -1)).isNull();}

Page 22: Tomasz Polanski - Droidcon Berlin 2016

Simple to understand?

Page 23: Tomasz Polanski - Droidcon Berlin 2016

Arrange Act Assert

Page 24: Tomasz Polanski - Droidcon Berlin 2016

@Testpublic void insertBuilder_withTable_withColumn_doesNotThrow() { new Builder().table(TABLE) .addColumn(COLUMN1) .build();}

@Test(expected = IllegalStateException.class)public void insertBuilder_withoutColumns_throwsException() { new Builder().table(TABLE) .build();}

Similar tests

Tomasz Polański
complex tests should differ only by one thing from the previous one
Page 25: Tomasz Polanski - Droidcon Berlin 2016

Test setup@Testpublic void test() { List<Language> list = Arrays.asList(GERMAN, ENGLISH); Mockito.when(mDataModel.getSupportedLanguages()) .thenReturn(list); Mockito.when(mDataModel.getGreetingByLanguageCode(LanguageCode.EN)) .thenReturn("Hi!");

// The rest of the test}

Page 26: Tomasz Polanski - Droidcon Berlin 2016

Arrange builderclass ArrangeBuilder {

ArrangeBuilder withLanguages(Language... languages) { Mockito.when(mDataModel.getSupportedLanguages()) .thenReturn(Arrays.asList(languages)); return this; }

ArrangeBuilder withGreetings(LanguageCode code, String greeting) { Mockito.when(mDataModel.getGreetingByLanguageCode(code)) .thenReturn(greeting); return this; }}

Page 27: Tomasz Polanski - Droidcon Berlin 2016

@Testpublic void test() { List<Language> list = Arrays.asList(GERMAN, ENGLISH); Mockito.when(mDataModel.getSupportedLanguages()) .thenReturn(list); Mockito.when(mDataModel.getGreetingByLanguageCode(LanguageCode.EN)) .thenReturn("Hi!");

// The rest of the test}

@Testpublic void test() { new ArrangeBuilder() .withLanguages(GERMAN, ENGLISH) .withGreetings(LanguageCode.EN, "Hi!");

// The rest of the test}

Arrange builder

Page 28: Tomasz Polanski - Droidcon Berlin 2016

Simple to write

Page 29: Tomasz Polanski - Droidcon Berlin 2016

Is it all?

Page 30: Tomasz Polanski - Droidcon Berlin 2016

Do I have enough tests?

Page 31: Tomasz Polanski - Droidcon Berlin 2016

static boolean isEven(int number) { return number % 2 == 0;}

static boolean isEven(int number) { return number % 2 == 0 ? true : false;}

What’s the code coverage?

@Testpublic void isTwoEven() { assertThat(isEven(2))

.isTrue();}

static boolean isEven(int number) { if ( number % 2 == 0 ) { return true; } else { return false; }}

Page 32: Tomasz Polanski - Droidcon Berlin 2016

What’s the code coverage?Observable<Boolean> isEven(int number) { return Observable.just(number) .map(num -> num % 2 == 0);}

@Testpublic void isTwoEven() { TestSubscriber<Boolean> ts = new TestSubscriber<>();

isEven(2).subscribe(ts);

ts.assertValue(true);}

@Testpublic void isTwoEven() { TestSubscriber<Boolean> ts = new TestSubscriber<>();

isEven(2).subscribe(ts);}

Page 33: Tomasz Polanski - Droidcon Berlin 2016

Do I have too many tests?

Page 34: Tomasz Polanski - Droidcon Berlin 2016

Do I have too much code?

Page 35: Tomasz Polanski - Droidcon Berlin 2016

public class Translation {

public final String mText;

public Translation(String text) { mText = text; }

public String text() { return mText; }} @AutoValue

public abstract class Translation {

public abstract String text(); public static Translation create(String text) { return new AutoValue_Translation(text); }}

. public class Translation {

private final String mText;

public Translation(String text) { mText = text; }

public String text() { return mText; }

@Override public int hashCode() { return mText != null ? mText.hashCode() : 0; }

@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false;

Translation that = (Translation) o;

return mText != null ? mText.equals(that.mText) : that.mText == null; }}

. @Testpublic void valueEquality() { String value = "text"; Translation first = Translation.create(value); Translation second = Translation.create(value); assertThat(first).isEqualTo(second);}

@AutoValuepublic abstract class Translation {

public abstract String text(); public static Translation create(String text) { return new AutoValue_Translation(text); }

@Override public int hashCode() { // ... }

@Override public boolean equals(Object o) { // ... }

}

Page 36: Tomasz Polanski - Droidcon Berlin 2016

What is this code here?

Observable<String> getCurrentLanguage() { return getSystemLanguage() .skip(1) .first();}

Observable<String> getCurrentLanguage() { return getSystemLanguage() // .skip(1) .first();}

Page 37: Tomasz Polanski - Droidcon Berlin 2016

Test Driven Development

Less Code Less Tests Peace of mind

Page 38: Tomasz Polanski - Droidcon Berlin 2016

Be playful Don’t be dogmatic

Find a test mentor

Page 39: Tomasz Polanski - Droidcon Berlin 2016
Page 40: Tomasz Polanski - Droidcon Berlin 2016

“Everyone knows that debugging is twice as hard as writing a program in the first place.

So if you're as clever as you can be when you write it, how will you

ever debug it?”Brian Kernighan

Page 41: Tomasz Polanski - Droidcon Berlin 2016

Thank you!

tpolansk