Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
MCE2015 - Automated Testing for Modern Android ...
Search
Andy Dyer
February 06, 2015
Programming
1.5k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
MCE2015 - Automated Testing for Modern Android Applications
Andy Dyer
February 06, 2015
More Decks by Andy Dyer
See All by Andy Dyer
AppCraft: Faster Than a Speeding Release Train
abdyer
1
370
Multiple Developers, One App: How to Not Break Everything
abdyer
0
390
Things That Suck About Android Development
abdyer
0
620
Building an Android Wear app
abdyer
0
110
BABBQ5 - Automated Testing for Modern Android Applications
abdyer
14
3.8k
Other Decks in Programming
See All in Programming
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
210
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
180
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
140
VibeCodingからAgenticWorkflowへ
starfish719
0
270
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
370
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
140
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
240
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
200
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
290
霧の中の代数的エフェクト
funnyycat
1
470
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
150
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
270
Featured
See All Featured
Six Lessons from altMBA
skipperchong
29
4.4k
Faster Mobile Websites
deanohume
310
32k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
650
Facilitating Awesome Meetings
lara
57
7.1k
Designing Experiences People Love
moore
143
24k
How to make the Groovebox
asonas
2
2.3k
Technical Leadership for Architectural Decision Making
baasie
3
470
Writing Fast Ruby
sferik
630
63k
Producing Creativity
orderedlist
PRO
348
40k
Agile that works and the tools we love
rasmusluckow
331
22k
The Invisible Side of Design
smashingmag
301
52k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.7k
Transcript
Automated Testing for Modern Android Applications
Andy Dyer +AndrewDyer @dammitandy
None
Making Android apps testable
Dynamic languages Tests shouldn't drive implementation.
Static languages You know nothing.
Making Android apps testable 1. Dependency injection 2. Mocking &
stubbing 3. Unit & integration tests
Dependency injection
Dependency injection • Classes receive dependencies, don’t have to know
where to find them or how to create them • Swap components for mocks in tests • Use different components for different build flavors, etc.
Basic dependency injection public class Beer implements Reinheitsgebot { Water
water; Barley barley; Hops hops; public Beer(Water water, Barley barley, Hops hops) { this.water = water; this.barley = barley; this.hops = hops; } }
Dagger A Java dependency injection library
Dagger • Defining dependencies at compile time avoids reflection at
runtime • Compiler validates components, modules, and injections • Dagger 2 is currently in alpha, but already being used by Google in production apps google.github.io/dagger/
Dagger Modules @Module public class MyModule { @Provides @Singleton public
MyService provideMyService() { return new MyService(); } }
Dagger Components @Component(modules = MyModule.class) public interface Graph { void
inject(Activity activity); void inject(Fragment fragment); public final static class Initializer { public static Graph init(boolean mockMode) { return Dagger_Graph.builder().build(); } } }
Dagger Object Graph public class MyApplication extends Application { @Getter
static DemoApplication instance; @Getter Graph graph; @Override public void onCreate() { super.onCreate(); instance = this; graph = Graph.Initializer.init(false); } public void setMockMode(boolean useMock) { graph = Graph.Initializer.init(useMock); } }
Dagger dependency injection public class MyFragment extends Fragment { @Inject
MyService service; @Override public void onViewCreated(View view, Bundle savedInstanceState) { MyApplication.getInstance().getGraph().inject(this); service.getMyData(); } }
Learning more about Dagger • Jake Wharton - Dependency Injection
with Dagger 2 parleys.com/play/5471cdd1e4b065ebcfa1d557 • Gregory Kick - Dagger 2: A New Type of Dependency Injection youtube.com/watch?v=oK_XtfXPkqw
Mocking & Stubbing
Mocking & Stubbing • Substitute runtime implementation for something that
can be predictably tested in isolation • Verify behavior
A Java mocking library
Mockito • Mock/stub dependencies and function return values • Inject
mocks to validate behavior in tests • Use included Hamcrest matchers for clear, readable tests code.google.com/p/mockito/
Using Mockito // create mock MyClass mocked = mock(MyClass.class); //
specify behavior when(mocked.doSomething()).thenReturn(somethingElse); // verify method calls verify(mocked).getMyData(anyInt(), anyString());
Using Mockito // capture arguments ArgumentCaptor<Callback> captor = ArgumentCaptor.forClass(Callback.class); verify(authenticationService).login(anyString(),
anyString(), captor.capture()); // simulate error conditions, etc. captor.getValue().failure(RetrofitError.unexpectedError( "Invalid password", new Exception()));
Unit & Integration Tests
Tests or it didn't happen
Unit testing public class BeerTest extends InstrumentationTestCase { @Inject Beer
beer; @Override protected void setUp() throws Exception { MyApplication.getInstance().getGraph().inject(this); } public void testBeerIsGood() { assertTrue(beer.isGood()); } }
An Android UI testing library
Espresso • Handles activity creation & state sync • Simple,
concise API • Really fast! code.google.com/p/android-test-kit*
UI testing with Espresso public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity> {
public MyActivityTest() { super(MyActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); getActivity(); // trigger activity launch } public void testInvalidEmailShowsError() { onView(withId(R.id.email)).perform(typeText("abc"), closeSoftKeyboard()); onView(withId(R.id.email_sign_in_button)).perform(click()); onView(withId(R.id.email)).check(matches(withError( getActivity().getString(R.string.error_invalid_email)))); } }
Sample application • Dagger object graph • Retrofit API with
sample request • Lombok & Android Studio plugin • Login activity • Activity with fragment to make API request and display data
Testing the login activity • Simulate data entry and taps
to validate UI functionality • Simulate an error without making a network request
Testing the main activity • Verify the RecyclerView contains data
• Simulate taps to validate the appropriate URLs are loaded in a WebView
Testing the API • Use mock API response loaded from
text file to validate JSON parsing
Demo
Known issues • Some tests may fail on older devices/emulators
such as those running < API 18. Hopefully this will be fixed soon by an update to the test support library.
Additional resources • Bryan Stern/Circle Engineering - Instrumentation Testing with
Dagger, Mockito, and Espresso engineering.circle.com/instrumentation-testing-with-dagger- mockito-and-espresso
Conclusion Using dependency injection, mocking, and automated testing tools helps
us build better apps. Working together as a community, we can make testing even easier.
Questions?
Slides speakerdeck.com/abdyer/mce2015-automated-testing-for- modern-android-applications Code github.com/abdyer/android-test-demo/releases/tag/ mceconf-2015 +AndrewDyer @dammitandy