The document discusses testing for Android applications. It covers different types of tests like unit tests, functional tests, integration tests and performance tests. It also discusses test frameworks in Android like InstrumentationTestCase, AndroidTestCase and ActivityInstrumentationTestCase2. The rest of the document talks about test driven development and how to write tests for an Android temperature converter application.
Breaking the Kubernetes Kill Chain: Host Path Mount
Android Testing Hands-On Approach
1. introduction to android
testing
a hands-on approach
OSCON 2012
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
1
2. diego torres milano
android system engineer
flextronics
http://dtmilano.blogspot.com
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
2
3. “Never test the depth of
the water with both feet.”
-- Anonymous
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
3
4. agenda
android testing background
test driven development
code coverage
continuous integration
behavior driven development
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
4
5. operating systems
May 2012
Others
iOS
250M
Android
400M
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
5
6. android testing
background
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
6
7. WhatWhy
When
how
?
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
7
8. types of test
tests
unit
functional
performance
integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
8
9. types of test
by programmers for programmers
unit
in a programming language
JUnit is the de-facto standard
test objects in isolation
in a repeatable way
usually rely on mock objects
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
9
10. types of test
tests
unit
functional
performance
integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
10
11. types of test
by business & QA people functional
in a business domain language
test completeness & correctness
BDD has gained some popularity
FitNesse can help
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
11
12. types of test
tests
unit
functional
performance
integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
12
13. types of test
how components work together integration
modules have been unit tested
android components need integration
with the system
testing framework facilitates
integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
13
14. types of test
tests
unit
functional
performance
integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
14
15. types of test
measure performance in a
performance repeatable way
if cannot be measure cannot be
improved
premature optimization does more
harm than good
measure-change-measure
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
15
16. types of test
tests
unit
functional
performance
integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
16
17. class diagram
Assert
<<iface>>
TestCase
Test
InstrumentationTestCase AndroidTestCase
ActivityInstrumentationTestCase2
ActivityUnitTestCase
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
17
18. InstrumentationTestCase
instrumentation instantiated
before application
allows for monitoring
interaction
send keys and input events
manual lifecycle
direct or indirect base
class of other tests
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
18
19. class diagram
Assert
<<iface>>
TestCase
Test
InstrumentationTestCase AndroidTestCase
ActivityInstrumentationTestCase2
ActivityUnitTestCase
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
19
20. ActivityUnitTestCase
isolated testing of single
Activity
minimal connection to
the system
uses mocks for
dependencies
some Activity methods
should not be called
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
20
21. class diagram
Assert
<<iface>>
TestCase
Test
InstrumentationTestCase AndroidTestCase
ActivityInstrumentationTestCase2
ActivityUnitTestCase
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
21
22. ActivityInstrumentationTestCase2
functional
testing of a single Activity
has access to Instrumentation
creates the AUT using system
infrastructure
custom intent can be provided
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
22
23. class diagram
Assert
<<iface>>
TestCase
Test
InstrumentationTestCase AndroidTestCase
ActivityInstrumentationTestCase2
ActivityUnitTestCase
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
23
24. access to Context AndroidTestCase
access to Resources
base class for Application, Provider
and Service test cases
Context stored in mContext field
can start more than one Activity
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
24
25. class diagram
Assert
<<iface>>
TestCase
Test
InstrumentationTestCase AndroidTestCase
ActivityInstrumentationTestCase2
ActivityUnitTestCase
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
25
27. test driven development advantages:
•the tests are written
one way or another
•developers take more
responsibility for the
quality of their work
strategy of writing tests along development
test cases written prior to the code
single test added, then the code to satisfy it
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
27
28. activity diagram
design decisions are
taken in single steps
and finally the code
write test satisfying the tests is
improved by
refactoring it
run
[fails]
code
[passes]
refactor
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
28
29. temperature converter
Title
celsius
100
autoupdate
32
fahrenheit
keyboard
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
29
30. 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
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
30
31. 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
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
31
32. github
$ mkdir myworkdir
$ cd myworkdir
$ git clone git://github.com/dtmilano/I2AT-
OSCON-2012.git
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
32
33. creating the
main project
TemperatureConverter uses
conventional settings
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
33
34. select build
target
TemperatureConverter uses
Android 4.0.3
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
34
35. creating the test
project
Automatically selected values
for TemperatureConverterTest
project
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
35
36. running the tests
[13:21:28 - TemperatureConverterTest]
Launching instrumentation
android.test.InstrumentationTestRunner on
device XXX
[13:21:28 - TemperatureConverterlTest-local]
Failed to launch test
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
36
37. warning due to the
parameterized base class
creating the test
case
Use:
ActivityInstrumentationTestCase2
as the base class
TemperatureConverterActivity as
the class under test
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
37
38. creating test
stubs
Select: onCreate(Bundle) to
create a method stub
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
38
39. fix constructor
/**
* Constructor
* @param name
*/
public TemperatureConverterActivityTests(String name) {
super(TemperatureConverterActivity.class);
setName(name);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
39
40. running the tests
junit.framework.AssertionFailedError:
Not yet implemented at
com.dtmilano.i2at.tc.test.
TemperatureConverterActivityTests.
testOnCreateBundle(
TemperatureConverterActivityTests.java:50)
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
40
41. fixture
protected void setUp(String name) throws Exception {
super.setUp();
mActivity = getActivity(); references the
assertNotNull(mActivity); main package
mCelsius = (EditText)mActivity.findViewById(
com.dtmilano.i2at.tc.R.id.celsius);
assertNotNull(mCelsius);
mFahrenheit = (EditText)mActivity.findViewById(com...);
assertNotNull(mFahrenheit);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
41
42. layout
satisfy the test needs
assign celsius and
fahrenheit ids
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
42
43. fix the test
! /**
! * Test method for {@link TemperatureConverterActivity
#onCreate(android.os.Bundle)}.
! */
! public void testOnCreateBundle() {
! ! assertNotNull(mActivity);
! }
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
43
44. ui tests: visibility
@SmallTest
public void testFieldsOnScreen() {
final View origin =
mActivity.getWindow().getDecorView();
ViewAsserts.assertOnScreen(origin, mCelsius);
ViewAsserts.assertOnScreen(origin, mFahrenheit);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
44
45. annotations
@SmallTest
@MediumTest
@LargeTest
@UiThreadTest
@Suppress
@FlakyTest
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
45
46. ui tests: alignment
@SmallTest
public void testAlignment() {
! ! ViewAsserts.assertRightAligned(mCelsius,
mFahrenheit);
! ! ViewAsserts.assertLeftAligned(mCelsius,
mFahrenheit);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
46
47. ui tests: initialization
@SmallTest
public void testFieldsShouldStartEmpty() {
! ! assertTrue("".equals(mCelsius.getText()
.toString()));
! ! assertTrue("".equals(mFahrenheit.getText()
.toString()));
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
47
48. ui tests: justification
@SmallTest
public void testJustification() {
! ! final int expected =
Gravity.RIGHT|Gravity.CENTER_VERTICAL;
! ! assertEquals(expected,
mCelsius.getGravity());
! ! assertEquals(expected,
mFahrenheit.getGravity());
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
48
49. running the tests
video plays on
click >>>
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
49
50. gravity
add right and
center_vertical
gravity for
celsius
and fahrenheit
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
50
51. running the tests
video plays on
click >>>
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
51
52. temperature conversion run on the
! @UiThreadTest main thread
! public void testFahrenheitToCelsiusConversion() {
specialized
! ! mCelsius.clear(); class
! ! mFahrenheit.clear(); errors are
underlined in red
! ! final double f = 32.5;
! ! mFahrenheit.requestFocus();
! ! mFahrenheit.setNumber(f);
converter
! ! mCelsius.requestFocus(); helper
! ! final double expected =
TemperatureConverter.fahrenheitToCelsius(f);
! ! final double actual = mCelsius.getNumber();
! ! final double delta = Math.abs(expected - actual);
! ! assertTrue(delta < 0.005);
! }
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
52
53. EditNumber class
EditNumber class
extends EditText
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
53
54. TemperatureCon
verter
TemperatureConverter
is a helper class
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
54
55. refactor
public class TemperatureConverterActivityTests
extends ActivityInstrumentationTestCase2<
TemperatureConverterActivity> {
private TemperatureConverterActivity
mActivity; new class
private EditNumber mCelsius;
private EditNumber mFahrenheit;
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
55
56. temperature conversion
! @UiThreadTest
! public void testFahrenheitToCelsiusConversion() {
! ! mCelsius.clear();
! ! mFahrenheit.clear(); all compiler errors
! ! final double f = 32.5; corrected
! ! 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);
! }
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
56
58. exception in logcat
java.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);
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
58
59. change widget
type
Select
com.dtmilano.i2at.tc.EditNum
ber
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
59
60. 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>
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
60
61. running the tests
what?
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
61
62. celsius to fahrenheit
Fahrenheit
150
112.5
75
f = 9/5 * c + 32
37.5
0
c = (f-32) * 5/9
-37.5
-75
-40 -30 -20 -10 0 10 20 30 40
Celsius
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
62
63. converter
public class TemperatureConverter {
! public static double fahrenheitToCelsius(double f) {
/ TODO Auto-generated method stub
/
! ! return 0;
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
63
64. TemperatureConv
erterTests
Test case as base class
create method stubs
TemperatureConverter as
CUT
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
64
65. method stubs
select the methods you want
stubs created for
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
65
66. 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);
! ! }
! }
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
66
68. add f -> c conversion
public class TemperatureConverter {
! public static double fahrenheitToCelsius(double f) {
! ! return (f-32) * 5/9.0;
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
68
69. run the tests
this assertion
fails
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
69
70. creating test
case
use AndroidTestCase as base
class
use EditNumber as CUT
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
70
71. method stubs
select the constructors
select other methods
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
71
72. fixture
/* (non-Javadoc)
* @see android.test.AndroidTestCase#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
mEditNumber = new EditNumber(getContext());
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
72
73. 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);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
73
74. implementation
public class EditNumber extends EditText {
/ ...
/
! public void clear() {
! ! setText(null);
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
74
75. test set number
public final void testSetNumber() {
final double expected = 123.45;
mEditNumber.setNumber(expected);
final double actual =
mEditNumber.getNumber();
assertEquals(expected, actual);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
75
76. set number
public class EditNumber extends EditText {
/ ...
/
public void setNumber(double f) {
setText(Double.toString(f));
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
76
77. test get number
public final void testGetNumber() {
! ! final double expected = 123.45;
! ! mEditNumber.setNumber(expected);
! ! final double actual =
mEditNumber.getNumber();
! ! assertEquals(expected, actual);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
77
78. get number
public class EditNumber extends EditText {
/ ...
/
! public void getNumber() {
final String s = getText().toString();
if ( "".equals(s) ) {
return Double.NaN;
}
! ! return Double.valueOf(s);
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
78
79. run the tests
testFahrenheitToCelsiusConversion
is still failing
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
79
80. what’s the problem ?
clear() works
requestFocus() works
setNumber() works
fahrenheitToCelsius() works
getNumber() works
so ?
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
80
81. temperature converter
Title
celsius
100
autoupdate
32
fahrenheit
keyboard
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
81
82. TemperatureChan
geWatcher
create it as an inner class
check abstract
implements TextWatcher
inherited abstract methods
create 2 EditNumber fields
mSource & mDest
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
82
83. generate
constructor
use the fields
public access
omit call to super()
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
83
84. the watcher
public abstract class TemperatureChangeWatcher
implements TextWatcher {
! ! private EditNumber mSource;
! ! private EditNumber mDest;
! !
! ! public TemperatureChangeWatcher(
EditNumber source, EditNumber dest) {
! ! ! this.mSource = source;
! ! ! this.mDest = dest;
! ! }
/ ...
/
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
84
85. on text changed
@Override
public 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; we should define
! } it
! 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());
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
85
86. abstract convert method
public abstract class TemperatureChangeWatcher
implements TextWatcher {
//...
protected abstract double convert(double temp);
//...
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
86
87. find views
@Override
public 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);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
87
88. add change listeners
@Override
public void onCreate(Bundle savedInstanceState) {
/ ...
/
mCelsius.addTextChangedListener(
we should create
new TemperatureChangeWatcher(mCelsius, mFahrenheit) {
it
! ! ! @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);
! ! ! }
});
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
88
89. add conversion
public 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;
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
89
90. adding test
public 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);
! ! }
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
90
92. implementing conversion
public 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;
! }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
92
94. test xml attributes
public 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());
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
94
95. decimal places
public 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;
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
95
96. define attributes
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="i2at">
<attr name="decimalPlaces" format="integer" />
</declare-styleable>
</resources>
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
96
97. 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>
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
97
98. 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();
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
98
99. know decimal places
protected void setUp() throws Exception {
super.setUp();
mEditNumber =
new EditNumber(getContext());
mEditNumber.setDecimalPlaces(2);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
99
100. test signed number
@SmallTest
public 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);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
100
101. 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>
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
101
104. code coverage
measures the amount of source code tested
android relies on emma (http://emma.sf.net)
supported coverage types:
class
method
line
block
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
104
105. coverage report
overall coverage summary
overall stats summary
coverage breakdown by package
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
105
106. building with ant
disable 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
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
106
107. run
configuration
run build.xml as Ant build... clean, emma,
use emma transient target debug, install,
test
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
107
108. ant 1.8
specify ant 1.8 home
Ant home...
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
108
109. 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
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
109
110. on some user devs
Give the app
WRITE_EXTERNAL_S
TORAGE permission
Add emma.dump.file
build property
Use an external
storage location (i.e.
sdcard)
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
110
117. 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);
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
117
118. finished
application
this is the final result
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
118
119. 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
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
119
123. am instrument
Waits until the
-w instrumentation terminates
before terminating itself
Outputs results in raw
-r
format
-e <key> Provides testing options as
<value> key-value pairs
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
123
124. command line
all tests:
$ adb shell am instrument -w
com.dtmilano.i2at.tc.test/
android.test.InstrumentationTestRunner
functional tests:
$ adb shell am instrument -w
-e func true
com.dtmilano.i2at.tc.test/
android.test.InstrumentationTestRunner
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
124
125. Activity
public class TemperatureConverterTestsActivity
extends Activity {
! private static final String TAG =
"TemperatureConverterTestsActivity";
! private static final int TIMEOUT = 15000;
!
! private TextView mResults;
! private LogcatAsyncTask mLogcat;
...
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
125
126. lifecycle methods
@Override
protected void onCreate(Bundle savedInstanceState) {
! ! super.onCreate(savedInstanceState);
! ! setContentView(R.layout.main);
! ! mResults = (TextView) findViewById(R.id.results);
}
@Override
protected void onDestroy() {
! ! super.onDestroy();
! ! if (mLogcat != null) { mLogcat.cancel(true); }
}
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
126
133. continuous integration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
133
134. continuous integration
agile technique for software engineering
received broad adoption in recent years
prevents “integration hell”
integrate changes frequently
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
134
145. test project
Create test project
Set repository URL
Trigger build after main project
Build with ant
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
145
146. xml test results
download xmlinstrumentationtestrunner.jar
replace instrumentation by
android:name="com.neenbedankt.android.test.
XMLInstrumentationTestRunner"
customize project configuration
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
146
150. coverage trend
Enable record emma coverage
Specify emma XML report files
Change health reporting
Modify build.xml to support XML reports
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
150
153. behavior driven
development
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
153
154. behavior driven
development
evolution of Test Driven Development
inclusion of business participant
common vocabulary
based on Neuro Linguistics Programming
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
154
160. 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
Copyright (C) 2011-2012 Diego Torres Milano All rights reserved
160