TDD Android Applications with Robolectric
Upcoming SlideShare
Loading in...5
×
 

TDD Android Applications with Robolectric

on

  • 27,988 views

Running tests on an Android emulator or device is slow! ...

Running tests on an Android emulator or device is slow!
Wouldn’t it be nice to run your Android tests directly from inside your IDE? Robolectric is a unit test framework that de-fangs the Android SDK jar so you can test-drive the development of your Android app. Tests run inside the JVM on your workstation in seconds.

Statistics

Views

Total Views
27,988
Views on SlideShare
10,478
Embed Views
17,510

Actions

Likes
19
Downloads
195
Comments
0

18 Embeds 17,510

http://pivotal.github.com 8865
http://robolectric.org 4100
http://pivotal.github.io 3710
http://www.intexsoft.com 249
http://catchbug.wordpress.com 188
http://robolectric.github.io 154
http://localhost 111
https://my.iacsam.com 95
http://feeds.feedburner.com 9
http://webcache.googleusercontent.com 9
http://translate.googleusercontent.com 5
http://www.bankinform.ru 5
https://twitter.com 4
http://cache.baidu.com 2
http://justborrowit.heroku.com 1
http://hghltd.yandex.net 1
http://www.verious.com 1
http://192.168.0.54 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • vs Robotium\n
  • Demonstrate the tests running in IntelliJ\n\n
  • \n
  • \n\n
  • Robolectric does include Mockito, uses it sparingly.\n\nRobolectric is compatible with mocking frameworks!\n
  • \n\n
  • \n
  • Show a demonstration in IntelliJ of a fake object\n
  • Show a demonstration in IntelliJ of a fake object\n
  • Show a demonstration in IntelliJ of a fake object\n
  • Show a demonstration in IntelliJ of a fake object\n
  • Show a demonstration in IntelliJ of a fake object\n
  • \n
  • \n
  • \n
  • This means you can do operations like findViewById\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • the real view is helpful for calling back into listeners and such\n
  • helpful when calling back into listeners that want to pass the ‘real’ object to the listeners\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

TDD Android Applications with Robolectric TDD Android Applications with Robolectric Presentation Transcript

  • Android Unit Test Frameworkhttp://pivotal.github.com/robolectric Follow us on twitter: @robolectric
  • Joe Moore @joem Pivotal Labs @pivotallabshttp://svy.mk/robolectric
  • DisclaimerI’m mostly a Ruby guy now
  • AgendaTesting Approaches and AlternativesHow Robolectric worksWorkshop - TDD and SetupHow to extend Robolectric
  • Agile web consulting companyRuby on Rails, Android and iOSXP, TDD, Pair ProgrammingSF, NYC, Boulder, Singapore… and Atlanta!
  • We Test Stuff Cedar BDD for iOSJsUnit
  • On to the Android!
  • java.lang.RuntimeException(“Stub!”)
  • Google stripped the classes in android.jar and replaced their method bodies with:java.lang.RuntimeException(“Stub!”)
  • Every Test Failsjava.lang.RuntimeException: Stub! at android.content.Context.<init>(Context.java:4) at android.content.ContextWrapper.<init>(ContextWra atandroid.view.ContextThemeWrapper.<init>(ContextThemeWr5) at android.app.Activity.<init>(Activity.java:6) at com.pivotallabs.NamesActivity.<init>(NamesActivi
  • Additional Android testing challengesMany of the classes and methods are finalLack of interfacesNon public constructorsstatic methods
  • It’s Getting Better CalculonA testing DSL for Google Android
  • How have you been testing?
  • Android Testing
  • Android Testing• F@*#-it!
  • Android Testing• F@*#-it!• Integration-style: Android InstrumentationTests/Robotium
  • Android Testing• F@*#-it!• Integration-style: Android InstrumentationTests/Robotium• Library of tested POJO’s
  • Android Testing• F@*#-it!• Integration-style: Android InstrumentationTests/Robotium• Library of tested POJO’s• Mocking framework
  • Why use Robolectric?
  • vs. Android Instrumentation Tests? Instrumentation Tests are SLOW Instrumentation Tests require dexing, packaging and installation on an emulator or device to run in the Dalvik VM.
  • vs. Android Instrumentation Tests? Robolectric runs in the regular JVM: FAST No dexing, packaging, deploying, etc. The latest Pivotal Android project is using Robolectric:1,047 tests run in 28 seconds!
  • vs. POJO lib approach?Test ALL your code, not just non-Androidcode -- increased test coverage.… But well-tested code libraries are still agood idea.
  • vs. POJO lib approach?Robolectric is compatible with the waymost Android developers work:putting lots of stuff in Activities vs. havingcomplex object models.
  • vs. Mock approach?Mocking frameworks can lead to tests thatare reverse implementation of the codeCan lead to tests that are hard to readCan lead to tests that don’t help refactoring
  • Robolectric lets you:Iterate quicklyWrite black box style of testsTest behavior instead of implementationHave high test coverage
  • How does it work?Shadow ObjectsView and Resource Loading
  • How does it work? Shadow ObjectsMaybe they should have been called proxies.
  • How does it work? Shadow Objects1. Robolectric intercepts the loading of Android classes under test
  • How does it work? Shadow Objects1. Robolectric intercepts the loading of Android classes under test2. Rewrites the method bodies of Android classes (using javassist)
  • How does it work? Shadow Objects1. Robolectric intercepts the loading of Android classes under test2. Rewrites the method bodies of Android classes (using javassist)3. Binds “shadow objects” to new Android objects
  • How does it work? Shadow Objects1. Robolectric intercepts the loading of Android classes under test2. Rewrites the method bodies of Android classes (using javassist)3. Binds “shadow objects” to new Android objects4. The modified Android objects then proxy
  • How does it work? Shadow Objects Shadow Button getText()myButton.getText() Button (Android) return “Okay” return “Okay” text=“Okay”
  • How does it work? Shadow Objects ShadowmyButton.getSomething() Button getSomething() Button (Android) return null; Does not implement getSomething()
  • How does it work? Shadow Objects• Shadows are proxies for the Android classes• i.e. ShadowImageView “shadows” ImageView• AndroidObject.someMethod() => proxies to => ShadowAndroidObject.someMethod()• State is recorded so it can be verified in tests
  • How does it work? View and Resource Loading• Robolectric parses layout files and builds a view object tree made of Android view objects and their shadows.• Many view xml attributes are applied to the view object• Strings, string arrays, and color resources
  • How can I get started?• http://pivotal.github.com/robolectric/ index.html• http://github.com/pivotal/ RobolectricSample
  • Robolectric IDE• We are IntelliJ guys• Eclipse works, too• Maven!
  • Writing Tests
  • Writing TestsTests that reference Android need to be annotated: ... @RunWith(RobolectricTestRunner.class) public class MyActivityTest { @Test public void shouldDoWizbangFooBar() { ...
  • Writing Tests Often Robolectric is InvisibleButton pressMeButton = homeActivity.findViewById(R.id.press_me_button);assertThat((String) pressMeButton.getText(), equalTo("Tests Rock!"));
  • Writing Tests Often Robolectric is InvisibleButton pressMeButton = homeActivity.findViewById(R.id.press_me_button);assertThat((String) pressMeButton.getText(), equalTo("Tests Rock!")); No sign of Robolectric, Shadows, etc.
  • Writing Tests Talking to ShadowsShadowActivity shadowActivity = shadowOf(homeActivity);Intent startedIntent = shadowActivity.getNextStartedActivity();ShadowIntent shadowIntent = shadowOf(startedIntent);
  • Writing Tests Talking to ShadowsShadowActivity shadowActivity = shadowOf(homeActivity);Intent startedIntent = shadowActivity.getNextStartedActivity();ShadowIntent shadowIntent = shadowOf(startedIntent); Many test-only methods are added to Shadow classes
  • Writing Tests Talking to ShadowsShadowActivity shadowActivity = shadowOf(homeActivity);Intent startedIntent = shadowActivity.getNextStartedActivity();ShadowIntent shadowIntent = shadowOf(startedIntent); Many test-only methods are added to Shadow classes Example: capturing object state
  • Writing Tests Talking to Shadows<ImageView android:id=”@+id/logo” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:src=”@drawable/logo” />...@Testpublic void logoImageViewShouldUseTheLogoDrawable() { ImageView logo = (ImageView) activity.findViewById(R.id.logo); // imageView only provides logo.getDrawable(); ShadowImageView logoShadow = Robolectric.shadowOf(logo); assertThat(logoShadow.resourceId, equalTo(R.drawable.logo));}
  • Extending Robolectric Help Robolectric cover more of Android
  • Writing Shadow• @RealObject• __constructor__• @Implements• @Implementation• Robolectric.bindAllShadowClasses()
  • Shadow Objects @RealObject• Robolectric is using reflection to instantiate the shadow object (default or no-args constructor)• Robolectric will inject the Android object onto shadow object’s fields annotated with @RealObject
  • Shadow Objects @RealObject@Implements(View.class)public class ShadowView { @RealObject private View realView; private int id;...
  • Shadow ObjectsShadow inheritance works.If no shadow class is registered for anAndroid class, the Android object’s superconstructor will seek out a shadow class,up through the constructor super chain untilone is found.
  • Shadow Objects__constructor__Implementations of Android constructors.When Robolectric is finished instantiatingthe shadow object, it will attempt to invokea method on the shadow named__constructor__ that has the sameargs as the Android object’s constructor
  • Shadow Objectspublic class Intent { public Intent(String action, Uri uri) { /* compiled code */ } ...}public class ShadowIntent { public void __constructor__(String action,Uri uri) { ... } ...}
  • Shadow Objects@Implements(View.class)public class ShadowView { @RealObject private View realView; private int id;...
  • Shadow Objectspublic class ShadowTextView {... @Implementation public CharSequence getText() { return text; }...
  • Shadow ObjectsRobolectric.bindAllShadowClasses() • Where shadow objects are registered into Robolectric • This is a current listing of all the shadow objects provided by Robolectric
  • Thanks! Joe Moore @joem Pivotal Labs @pivotallabshttp://svy.mk/robolectric