tomasz polanski - droidcon berlin 2016

Post on 17-Feb-2017

377 Views

Category:

Mobile

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

TESTING

Tomek Polanskitpolansk

WHY?WHEN?HOW?

“Too much time pressure with making visible changes.

Customer doesn't appreciate tests enough.”

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

prototypes or early MVPs.”

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

constantly.”

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

“Nobody else in the project uses them.

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

Time and budget“Too much time

pressure with making visible changes”

Instant changes Return on investment

vs

Speed

“Not for prototypes or early MVPs”

Time

Prog

ress

without tests

with tests

Prototype

Minimum Viable Product

Lovable

by Henrik Kniberg

Constant ChangeThe

“Specs are too volatile”

Programming is hard

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

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

Architecture

“Tests are hard and difficult to understand”

Maintenance

“Missing/broken tests”

What should unit tests look like?

Fast

Reliable

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();}

Simple to understand?

Arrange Act Assert

@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

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}

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; }}

@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

Simple to write

Is it all?

Do I have enough tests?

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; }}

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);}

Do I have too many tests?

Do I have too much code?

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) { // ... }

}

What is this code here?

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

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

Test Driven Development

Less Code Less Tests Peace of mind

Be playful Don’t be dogmatic

Find a test mentor

“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

Thank you!

tpolansk

top related