Transcript
Page 1: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

introduction to android testing

a hands-on approachOSCON 2012

1

Page 2: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

diego torres milanoandroid system engineer

flextronics

http://dtmilano.blogspot.com

2

Page 3: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

“Never test the depth of the water with both feet.”

-- Anonymous

3

Page 4: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

agenda

android testing background

test driven development

code coverage

continuous integration

behavior driven development

4

Page 5: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

operating systems

Others

Android400M

iOS250M

May 2012

5

Page 6: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

android testing background

6

Page 7: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

?WhenWhat

howWhy

7

Page 8: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of testtests

unit functional

integration performance

8

Page 9: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of test

unitby programmers for programmers

in a programming language

JUnit is the de-facto standard

test objects in isolation

in a repeatable way

usually rely on mock objects

9

Page 10: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of testtests

unit functional

integration performance

10

Page 11: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of test

by business & QA people

in a business domain language

test completeness & correctness

BDD has gained some popularity

FitNesse can help

functional

11

Page 12: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of testtests

unit functional

integration performance

12

Page 13: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of test

how components work together

modules have been unit tested

android components need integration with the system

testing framework facilitates integration

integration

13

Page 14: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of testtests

unit functional

integration performance

14

Page 15: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of testmeasure performance in a repeatable way

if cannot be measure cannot be improved

premature optimization does more harm than good

measure-change-measure

performance

15

Page 16: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

types of testtests

unit functional

integration performance

16

Page 17: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

class diagramAssert

TestCase<<iface>>Test

AndroidTestCaseInstrumentationTestCase

ActivityInstrumentationTestCase2

ActivityUnitTestCase

17

Page 18: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

InstrumentationTestCaseinstrumentation instantiated before application

allows for monitoring interaction

send keys and input events

manual lifecycle

direct or indirect base class of other tests

18

Page 19: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

class diagramAssert

TestCase<<iface>>Test

AndroidTestCaseInstrumentationTestCase

ActivityInstrumentationTestCase2

ActivityUnitTestCase

19

Page 20: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

isolated testing of single Activity

minimal connection to the system

uses mocks for dependencies

some Activity methods should not be called

ActivityUnitTestCase

20

Page 21: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

class diagramAssert

TestCase<<iface>>Test

AndroidTestCaseInstrumentationTestCase

ActivityInstrumentationTestCase2

ActivityUnitTestCase

21

Page 22: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

functionaltesting of a single Activity

has access to Instrumentation

creates the AUT using system infrastructure

custom intent can be provided

ActivityInstrumentationTestCase2

22

Page 23: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

class diagramAssert

TestCase<<iface>>Test

AndroidTestCaseInstrumentationTestCase

ActivityInstrumentationTestCase2

ActivityUnitTestCase

23

Page 24: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

access to Context

access to Resources

base class for Application, Provider and Service test cases

Context stored in mContext field

can start more than one Activity

AndroidTestCase

24

Page 25: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

class diagramAssert

TestCase<<iface>>Test

AndroidTestCaseInstrumentationTestCase

ActivityInstrumentationTestCase2

ActivityUnitTestCase

25

Page 26: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test driven development

26

Page 27: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test driven development

strategy of writing tests along development

test cases written prior to the code

single test added, then the code to satisfy it

advantages:

•the tests are written one way or another

•developers take more responsibility for the quality of their work

27

Page 28: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

activity diagramwrite test

run

code

refactor

[passes]

[fails]

design decisions are taken in single steps and finally the code satisfying the tests is improved by refactoring it

28

Page 29: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

temperature converter

100

32

Title

fahrenheit

celsius

keyboard

autoupdate

29

Page 30: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

requirements

converts between temperature units

one temperature is entered and the other is updated

error is displayed in the field

right aligned, 2 decimal digits

entry fields start empty

30

Page 31: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

understanding requirements

to write a test you must understand the requirement

destination is quickly identified

if requirement change, changing the corresponding test helps verify it

31

Page 32: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

github

$mkdir myworkdir

$ cd myworkdir

$ git clone git://github.com/dtmilano/I2AT-OSCON-2012.git

32

Page 33: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

creating the main project

TemperatureConverter uses conventional settings

33

Page 34: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

select build target

TemperatureConverter uses Android 4.0.3

34

Page 35: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

creating the test project

Automatically selected values for TemperatureConverterTest

project

35

Page 36: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the tests

[13:21:28 - TemperatureConverterTest] Launching instrumentation android.test.InstrumentationTestRunner on device XXX[13:21:28 - TemperatureConverterlTest-local] Failed to launch test

36

Page 37: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

creating the test case

Use: ActivityInstrumentationTestCase2

as the base classTemperatureConverterActivity as

the class under test

warning due to the parameterized base class

37

Page 38: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

creating test stubs

Select: onCreate(Bundle) to create a method stub

38

Page 39: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

fix constructor/** * Constructor * @param name */public TemperatureConverterActivityTests(String name) { super(TemperatureConverterActivity.class); setName(name);}

39

Page 40: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the tests

junit.framework.AssertionFailedError: Not yet implemented at com.dtmilano.i2at.tc.test. TemperatureConverterActivityTests. testOnCreateBundle( TemperatureConverterActivityTests.java:50)

40

Page 41: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

fixtureprotected void setUp(String name) throws Exception { super.setUp();

mActivity = getActivity(); assertNotNull(mActivity);

mCelsius = (EditText)mActivity.findViewById( com.dtmilano.i2at.tc.R.id.celsius); assertNotNull(mCelsius); mFahrenheit = (EditText)mActivity.findViewById(com...); assertNotNull(mFahrenheit);}

references the main package

41

Page 42: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

layoutsatisfy the test needs

assign celsius and fahrenheit ids

42

Page 43: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

fix the test! /**! * Test method for {@link TemperatureConverterActivity #onCreate(android.os.Bundle)}.! */

! public void testOnCreateBundle() {! ! assertNotNull(mActivity);! }

43

Page 44: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

ui tests: visibility

@SmallTestpublic void testFieldsOnScreen() { final View origin = mActivity.getWindow().getDecorView(); ViewAsserts.assertOnScreen(origin, mCelsius); ViewAsserts.assertOnScreen(origin, mFahrenheit);}

44

Page 45: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

annotations@SmallTest

@MediumTest

@LargeTest

@UiThreadTest

@Suppress

@FlakyTest

45

Page 46: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

ui tests: alignment

@SmallTestpublic void testAlignment() {! ! ViewAsserts.assertRightAligned(mCelsius, mFahrenheit);! ! ViewAsserts.assertLeftAligned(mCelsius, mFahrenheit);}

46

Page 47: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

ui tests: initialization

@SmallTestpublic void testFieldsShouldStartEmpty() {! ! assertTrue("".equals(mCelsius.getText() .toString()));! ! assertTrue("".equals(mFahrenheit.getText() .toString()));}

47

Page 48: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

ui tests: justification @SmallTestpublic void testJustification() {! ! final int expected = Gravity.RIGHT|Gravity.CENTER_VERTICAL;! ! assertEquals(expected, mCelsius.getGravity());! ! assertEquals(expected, mFahrenheit.getGravity());}

48

Page 49: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the testsvideo plays on click >>>

49

Page 50: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

gravityadd right and center_vertical

gravity for celsius

and fahrenheit

50

Page 51: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the testsvideo plays on click >>>

51

Page 52: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

temperature conversion! @UiThreadTest! public void testFahrenheitToCelsiusConversion() {! ! mCelsius.clear();! ! mFahrenheit.clear();! ! final double f = 32.5;! ! mFahrenheit.requestFocus();! ! mFahrenheit.setNumber(f);! ! mCelsius.requestFocus();! ! final double expected = TemperatureConverter.fahrenheitToCelsius(f);! ! final double actual = mCelsius.getNumber();! ! final double delta = Math.abs(expected - actual);! ! assertTrue(delta < 0.005);! }

run on the main thread

specializedclass

converterhelper

errors are underlined in red

52

Page 53: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

EditNumber classEditNumber class extends EditText

53

Page 54: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

TemperatureConverter

TemperatureConverter is a helper class

54

Page 55: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

refactorpublic class TemperatureConverterActivityTests extends ActivityInstrumentationTestCase2< TemperatureConverterActivity> {

private TemperatureConverterActivity mActivity; private EditNumber mCelsius; private EditNumber mFahrenheit;

new class

55

Page 56: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

! @UiThreadTest! public void testFahrenheitToCelsiusConversion() {! ! mCelsius.clear();! ! mFahrenheit.clear();! ! final double f = 32.5;! ! mFahrenheit.requestFocus();! ! mFahrenheit.setNumber(f);! ! mCelsius.requestFocus();! ! final double expected = TemperatureConverter.fahrenheitToCelsius(f);! ! final double actual = mCelsius.getNumber();! ! final double delta = Math.abs(expected - actual);! ! assertTrue(delta < 0.005);! }

temperature conversion! @UiThreadTest! public void testFahrenheitToCelsiusConversion() {! ! mCelsius.clear();! ! mFahrenheit.clear();! ! final double f = 32.5;! ! mFahrenheit.requestFocus();! ! mFahrenheit.setNumber(f);! ! mCelsius.requestFocus();! ! final double expected = TemperatureConverter.fahrenheitToCelsius(f);! ! final double actual = mCelsius.getNumber();! ! final double delta = Math.abs(expected - actual);! ! assertTrue(delta < 0.005);! }

all compiler errors corrected

56

Page 57: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

OMG!

[TemperatureConverterTests-OSCON-2012] Test run failed: Instrumentation run failed due to 'Process crashed.'[TemperatureConverterTests-OSCON-2012] Test run finished

57

Page 58: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

exception in logcatjava.lang.ClassCastException: android.widget.EditText at com.dtmilano.i2at.tc.test. TemperatureConverterActivityTests.setUp (TemperatureConverterActivityTests.java: 52)

52:!! mCelsius = (EditNumber) mActivity.findViewById( com.dtmilano.i2at.tc.R.id.celsius);

58

Page 59: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

change widget typeSelect

com.dtmilano.i2at.tc.EditNumber

59

Page 60: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

layout

<com.dtmilano.i2at.tc.EditNumber android:layout_height="wrap_content"! ! android:layout_width="match_parent" android:inputType="numberDecimal"! ! android:id="@+id/celsius" android:gravity="right|center_vertical">! ! <requestFocus /></com.dtmilano.i2at.tc.EditNumber>

60

Page 61: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the tests

what?

61

Page 62: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

celsius to fahrenheit

-75

-37.5

0

37.5

75

112.5

150

-40 -30 -20 -10 0 10 20 30 40

Fahrenheit

Celsius

f = 9/5 * c + 32c = (f-32) * 5/9

62

Page 63: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

converter

public class TemperatureConverter {

! public static double fahrenheitToCelsius(double f) { // TODO Auto-generated method stub! ! return 0;! }

}

63

Page 64: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

TemperatureConverterTestsTest case as base classcreate method stubs

TemperatureConverter as CUT

64

Page 65: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

method stubsselect the methods you want

stubs created for

65

Page 66: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

conversion test

public final void testFahrenheitToCelsius() {! ! for (double c: sConversionTableDouble.keySet()) {! ! ! final double f = sConversionTableDouble.get(c);! ! ! final double ca = TemperatureConverter.fahrenheitToCelsius(f);! ! ! final double delta = Math.abs(ca - c);! ! ! assertTrue(delta < 0.005);! ! }! }

66

Page 67: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

conversion tableprivate static final HashMap<Double, Double> sConversionTableDouble =! ! ! new HashMap<Double, Double>();!static {! ! sConversionTableDouble.put(0.0, 32.0);! ! sConversionTableDouble.put(100.0, 212.0);! ! sConversionTableDouble.put(-1.0, 30.20);! ! sConversionTableDouble.put(-100.0, -148.0);! ! sConversionTableDouble.put(32.0, 89.60);! ! sConversionTableDouble.put(-40.0, -40.0);! ! sConversionTableDouble.put(-273.0, -459.40);}

67

Page 68: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

add f -> c conversion

public class TemperatureConverter {

! public static double fahrenheitToCelsius(double f) {! ! return (f-32) * 5/9.0;! }

}

68

Page 69: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

run the tests

this assertion fails

69

Page 70: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

creating test case

use AndroidTestCase as base class

use EditNumber as CUT

70

Page 71: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

method stubsselect the constructorsselect other methods

71

Page 72: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

fixture

/* (non-Javadoc) * @see android.test.AndroidTestCase#setUp() */protected void setUp() throws Exception { super.setUp(); mEditNumber = new EditNumber(getContext());

}

72

Page 73: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test

public final void testClear() {! ! final String value = "123.45";! ! mEditNumber.setText(value);! ! mEditNumber.clear();! ! final String expected = "";! ! final String actual = mEditNumber.getText().toString();! ! assertEquals(expected, actual);}

73

Page 74: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

implementation

public class EditNumber extends EditText {

// ...

! public void clear() {! ! setText(null);! }

}

74

Page 75: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test set number

public final void testSetNumber() { final double expected = 123.45; mEditNumber.setNumber(expected); final double actual = mEditNumber.getNumber(); assertEquals(expected, actual);}

75

Page 76: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

set number

public class EditNumber extends EditText {

// ...

public void setNumber(double f) { setText(Double.toString(f)); }

76

Page 77: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test get number

public final void testGetNumber() {! ! final double expected = 123.45;! ! mEditNumber.setNumber(expected);! ! final double actual = mEditNumber.getNumber();! ! assertEquals(expected, actual);}

77

Page 78: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

get numberpublic class EditNumber extends EditText {

// ...

! public void getNumber() { final String s = getText().toString(); if ( "".equals(s) ) { return Double.NaN; }! ! return Double.valueOf(s);! }}

78

Page 79: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

run the tests

testFahrenheitToCelsiusConversion is still failing

79

Page 80: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

what’s the problem ?clear() works

requestFocus() works

setNumber() works

fahrenheitToCelsius() works

getNumber() works

so ?

80

Page 81: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

temperature converter

100

32

Title

fahrenheit

celsius

keyboard

autoupdate

81

Page 82: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

TemperatureChangeWatcher

create it as an inner classcheck abstractimplements TextWatcherinherited abstract methodscreate 2 EditNumber fields mSource & mDest

82

Page 83: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

generate constructor

use the fieldspublic accessomit call to super()

83

Page 84: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

the watcherpublic abstract class TemperatureChangeWatcher implements TextWatcher {! ! private EditNumber mSource;! ! private EditNumber mDest;! !! ! public TemperatureChangeWatcher( EditNumber source, EditNumber dest) {! ! ! this.mSource = source;! ! ! this.mDest = dest;! ! } // ...}

84

Page 85: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

on text changed@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {! if ( !mDest.hasWindowFocus() || mDest.hasFocus() || s == null ) return;! final String str = s.toString();! if ( "".equals(str) ) {! ! mDest.setText(""); return;! }! try {! ! final double result = convert(Double.parseDouble(str));! ! mDest.setNumber(result);! }! catch (NumberFormatException e) {! ! // WARNING: this is thrown while a number is entered, for example just a '-'! }! catch (Exception e) {! ! mSource.setError("ERROR: " + e.getLocalizedMessage());! }}

we should define it

85

Page 86: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

abstract convert method

public abstract class TemperatureChangeWatcher implements TextWatcher { //...

protected abstract double convert(double temp); //...}

86

Page 87: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

find views@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView( R.layout.activity_temperature_converter); mCelsius = (EditNumber) findViewById(R.id.celsius); mFahrenheit = (EditNumber) findViewById(R.id.fahrenheit);}

87

Page 88: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

add change listeners@Overridepublic void onCreate(Bundle savedInstanceState) { // ... mCelsius.addTextChangedListener( new TemperatureChangeWatcher(mCelsius, mFahrenheit) {! ! ! @Override protected double convert(double temp) {! ! ! ! return TemperatureConverter.celsiusToFahrenheit(temp);! ! ! }! }); mFahrenheit.addTextChangedListener( new TemperatureChangeWatcher(mFahrenheit, mCelsius) {! ! ! @Override protected double convert(double temp) {! ! ! ! return TemperatureConverter.fahrenheitToCelsius(temp);! ! ! } });}

we should create it

88

Page 89: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

add conversionpublic class TemperatureConverter {

! public static double fahrenheitToCelsius(double f) {! ! return (f-32) * 5/9.0;! }

! public static double celsiusToFahrenheit(double c) {! ! // TODO Auto-generated method stub! ! return 0;! }}

89

Page 90: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

adding testpublic class TemperatureConverterTests extends TestCase { // ...! /**! * Test method for {@link TemperatureConverter#fahrenheitToCelsius(double)}.! */! public final void testCelsiusToFahrenheit() {! ! for (double c: sConversionTableDouble.keySet()) {! ! ! final double f = sConversionTableDouble.get(c);! ! ! final double fa = TemperatureConverter.celsiusToFahrenheit(c);! ! ! final double delta = Math.abs(fa - f);! ! ! assertTrue("delta=" + delta + " for f=" + f + " fa=" + fa, delta < 0.005);! ! }! }}

90

Page 91: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the tests

91

Page 92: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

implementing conversionpublic class TemperatureConverter {

! public static double fahrenheitToCelsius(double f) {! ! return (f-32) * 5/9.0;! }

! public static double celsiusToFahrenheit(double c) {! ! return 9/5.0 * c + 32;! }}

92

Page 93: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the tests

93

Page 94: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test xml attributespublic final void testSetDecimalPlacesAttributeFromXml() { LayoutInflater inflater = (LayoutInflater)getContext() .getSystemService( Context.LAYOUT_INFLATER_SERVICE); View root = inflater.inflate( com.dtmilano.i2at.tc.R.layout.activity..., null); EditNumber editNumber = (EditNumber) root.findViewById(com.dtmilano.i2at.tc.R.id.celsius); assertNotNull(editNumber); // i2at:decimalPlaces="2" is set in main.xml assertEquals(2, editNumber.getDecimalPlaces());}

94

Page 95: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

decimal placespublic void setNumber(double d) { final String str = String.format("%." + mDecimalPlaces + "f", d); setText(str);}

public void setDecimalPlaces(int places) { mDecimalPlaces = places;} public int getDecimalPlaces() { return mDecimalPlaces;}

95

Page 96: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

define attributes

<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="i2at"> <attr name="decimalPlaces" format="integer" /> </declare-styleable> </resources>

96

Page 97: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

add attributes

xmlns:i2at="http://schemas.android.com/apk/res/com.dtmilano.i2at.tc"

<com.dtmilano.i2at.tc.EditNumber android:id="@+id/celsius" i2at:decimalPlaces="2" android:ems="10" ... > <requestFocus /> </com.dtmilano.i2at.tc.EditNumber>

97

Page 98: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

init using attributes

public EditNumber(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, -1);}

private void init(Context context, AttributeSet attrs, int defStyle) { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.i2at); setDecimalPlaces(a.getInteger( R.styleable.i2at_decimalPlaces, DEFAULT_DECIMAL_PLACES)); a.recycle();}

98

Page 99: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

know decimal places

protected void setUp() throws Exception { super.setUp(); mEditNumber = new EditNumber(getContext()); mEditNumber.setDecimalPlaces(2);}

99

Page 100: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test signed number@SmallTestpublic void testFahrenheitToCelsiusConversion_input() throws Throwable { runTestOnUiThread(new Runnable() { @Override public void run() { mCelsius.clear(); mFahrenheit.clear(); } }); final String c = "-123.4"; getInstrumentation().sendStringSync(c); assertEquals(c, mCelsius.getText().toString()); final double expected = TemperatureConverter.celsiusToFahrenheit(Double.parseDouble(c)); final double actual = mFahrenheit.getNumber(); final double delta = Math.abs(expected - actual); assertTrue(delta < 0.005);}

100

Page 101: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

add attributes<com.dtmilano.i2at.tc.EditNumber android:id="@+id/celsius" android:layout_width="match_parent" android:layout_height="wrap_content" i2at:decimalPlaces="2" android:ems="10" android:gravity="center_vertical|right" android:inputType="numberSigned|numberDecimal" > <requestFocus /></com.dtmilano.i2at.tc.EditNumber>

101

Page 102: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running the tests

102

Page 103: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

code coverage

103

Page 104: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

code coverage

measures the amount of source code tested

android relies on emma (http://emma.sf.net)

supported coverage types:

class

method

line

block

104

Page 105: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

coverage report

overall coverage summary

overall stats summary

coverage breakdown by package

105

Page 106: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

building with antdisable project’s Build Automatically in Eclipse

convert project to ant

$ android update project --path $PWD \ --name TemperatureConverter-OSCON-2012 \ --target android-15 --subprojects

$ android update test-project \ --main $PWD \ --path $PWD/tests

106

Page 107: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

run configuration

run build.xml as Ant build...use emma transient target

clean, emma, debug, install,

test

107

Page 108: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

ant 1.8specify ant 1.8 home

Ant home...

108

Page 109: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

coverage

run build.xml

coverage analysis report is generated

is currently only supported on the emulator and rooted devices

get coverage file

$ adb pull /data/data/com.example.i2at.tc/files/coverage.ec coverage.ec

109

Page 110: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

on some user devs

Give the app WRITE_EXTERNAL_STORAGE permission

Add emma.dump.file build property

Use an external storage location (i.e. sdcard)

110

Page 111: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

coverage report

111

Page 112: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

coverage breakdown

name class% method% block% line%

TemperatureConverter

TemperatureConverterActivity

EditNumber

100% 67% 82% 67%

100% 100% 91% 93%

100% 100% 98% 96%

112

Page 113: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

constructor not covered

113

Page 114: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

private constructorpublic class TemperatureConverter {! private TemperatureConverter() {! ! // do nothing! }! public static double fahrenheitToCelsius(double f) {! ! return (f-32) * 5/9.0;! }! public static double celsiusToFahrenheit(double c) {! ! return 9/5.0 * c + 32;! }}

114

Page 115: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

access private constructor

public final void testPrivateConstructor() throws Exception {! Constructor<TemperatureConverter> ctor = TemperatureConverter.class.getDeclaredConstructor();! ctor.setAccessible(true);! TemperatureConverter tc = ctor.newInstance((Object[])null);! assertNotNull(tc);}

circumventrestriction

115

Page 116: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

returning NaN

116

Page 117: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

missing tests

public final void testGetNumber_emptyText() { mEditNumber.setText(""); final double actual = mEditNumber.getNumber(); assertEquals(Double.NaN, actual);} public final void testGetNumber_nullText() { mEditNumber.setText(null); final double actual = mEditNumber.getNumber(); assertEquals(Double.NaN, actual);}

117

Page 118: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

finished application

this is the final result

118

Page 119: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

requirements

converts between temperature units

one temperature is entered and the other is updated

error is displayed in the field

right aligned, 2 decimal digits

entry fields start empty

119

Page 120: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

running tests

120

Page 121: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

alternatives

eclipse

command line

android application

121

Page 122: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

run configurations122

Page 123: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

am instrument

-wWaits until the

instrumentation terminates before terminating itself

-r Outputs results in raw format

-e <key> <value>

Provides testing options as key-value pairs

123

Page 124: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

command line$ adb shell am instrument -w \ com.dtmilano.i2at.tc.test/\ android.test.InstrumentationTestRunner

$ adb shell am instrument -w \ -e func true \ com.dtmilano.i2at.tc.test/\ android.test.InstrumentationTestRunner

all tests:

functional tests:

124

Page 125: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

Activitypublic class TemperatureConverterTestsActivity extends Activity {

! private static final String TAG = "TemperatureConverterTestsActivity";

! private static final int TIMEOUT = 15000;!! private TextView mResults;! private LogcatAsyncTask mLogcat;...

125

Page 126: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

lifecycle methods@Overrideprotected void onCreate(Bundle savedInstanceState) {! ! super.onCreate(savedInstanceState);! ! setContentView(R.layout.main);! ! mResults = (TextView) findViewById(R.id.results);}@Overrideprotected void onDestroy() {! ! super.onDestroy();! ! if (mLogcat != null) { mLogcat.cancel(true); }}

126

Page 127: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

getInstrumentationInfo

private InstrumentationInfo getInstrumentationInfo(final String packageName) {! ! final List<InstrumentationInfo> list = getPackageManager()! ! ! ! .queryInstrumentation(packageName, 0);! ! return (!list.isEmpty()) ? list.get(0) : null;}

127

Page 128: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

run testspublic void runTests(View v) { final String pn = getPackageName().replaceFirst(".test$", ""); final InstrumentationInfo info = getInstrumentationInfo(pn); if (info != null) {! final ComponentName cn = new ComponentName(info.packageName,! ! ! info.name);! if (startInstrumentation(cn, null, null)) {! ! mLogcat = new LogcatAsyncTask();! ! mLogcat.execute(TIMEOUT);! } } else {! Toast.makeText(this,! ! ! "Cannot find instrumentation for " + pn, Toast.LENGTH_SHORT) .show();! }}

128

Page 129: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

task to read logcatprivate class LogcatAsyncTask extends AsyncTask<Integer, String, Void> {! // TestRunner and silence others! private static final String CMD = "logcat -v time TestRunner:I *:S";! private BufferedReader mReader;! private Process mProc;

! public LogcatAsyncTask() {! ! try {! ! ! mProc = Runtime.getRuntime().exec(CMD);! ! ! mReader = new BufferedReader(new InputStreamReader(! ! ! ! ! mProc.getInputStream()));! ! } catch (Exception e) {! ! ! Log.e(TAG, "Creating proc", e);! ! }! }

129

Page 130: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

progress update

@Overrideprotected void onProgressUpdate(String... values) {! ! if (!TextUtils.isEmpty(values[0])) {! ! ! mResults.append("\n" + values[0]);! ! }}

130

Page 131: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

do in background@Overrideprotected Void doInBackground(Integer... params) {! ! final long timeout = System.currentTimeMillis() + params[0];! ! try {! ! ! do {! ! ! ! Thread.sleep(50); publishProgress(mReader.readLine());! ! ! } while (System.currentTimeMillis() < timeout);! ! } catch (Exception e) {! ! ! publishProgress("ERROR: " + e);! ! } finally {! ! ! publishProgress("END"); mProc.destroy();! ! }! ! return null;! }}

131

Page 132: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

in action132

Page 133: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

continuous integration

133

Page 134: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

continuous integration

agile technique for software engineering

received broad adoption in recent years

prevents “integration hell”

integrate changes frequently

134

Page 135: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

requirements

version control system

automated build

self tested

artifacts and tests results easy to find

135

Page 136: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

installation

download war from http://jenkins-ci.org

$ java -jar jenkins.war

136

Page 137: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

jenkins home

137

Page 138: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

android plugin

138

Page 139: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

new job

139

Page 140: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

ant properties

140

Page 141: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

build artifacts

141

Page 142: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

build dependency

142

Page 143: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

android emulator

143

Page 144: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

invoke ant

144

Page 145: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

Create test project

Set repository URL

Trigger build after main project

Build with ant

test project

145

Page 146: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

xml test results

download xmlinstrumentationtestrunner.jar

replace instrumentation byandroid:name="com.neenbedankt.android.test.XMLInstrumentationTestRunner"

customize project configuration

146

Page 147: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

junit test result

147

Page 148: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

build step

PKG=com.dtmilano.i2at.tcOUTDIR=/mnt/sdcard/Android/data/$PKG/files/OUTFILE=test-results.xmlADB=/opt/android-sdk/platform-tools/adb

$ADB pull "$OUTDIR/$OUTFILE" "$WORKSPACE/TemperatureConverter-OSCON-2012/tests/bin/$OUTFILE"

148

Page 149: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test report

149

Page 150: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

coverage trend

Enable record emma coverage

Specify emma XML report files

Change health reporting

Modify build.xml to support XML reports

150

Page 151: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

code coverage

151

Page 152: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

line coverage

152

Page 153: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

behavior driven development

153

Page 154: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

behavior driven development

evolution of Test Driven Development

inclusion of business participant

common vocabulary

based on Neuro Linguistics Programming

154

Page 155: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

fitnesse

155

Page 156: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test suite

156

Page 157: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

slim test fixturepackage com.example.i2at.tc.test.fitnesse.fixture;import com.example.i2at.tc.TemperatureConverter;

public class TemperatureConverterCelsiusToFahrenheitFixture {! private double celsius;

! public void setCelsius(double celsius) {! ! this.celsius = celsius;! }

! public String fahrenheit() throws Exception {! ! try {! ! ! return String.valueOf(TemperatureConverter.celsiusToFahrenheit(celsius));! ! } catch (RuntimeException e) {! ! ! return e.getLocalizedMessage();! ! }! }}

157

Page 158: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

test run

158

Page 159: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

questions ?

159

Page 160: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

android application testing guide

Apply testing techniques and tools• Learn the nuances of Unit and

Functional testing• Understand different development

methodologies such as TDD and BDD• Apply Continuous Integration• Improve applications using

performance tests• Expose your application to a wide

range of conditions

160

Page 161: Introduction to android testing - oscon 2012

Copyright (C) 2011-2012 Diego Torres Milano All rights reserved

thank you

161


Top Related