TDD Android Applications with Robolectric

30,443 views
30,199 views

Published on

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.

Published in: Technology
0 Comments
24 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
30,443
On SlideShare
0
From Embeds
0
Number of Embeds
17,756
Actions
Shares
0
Downloads
244
Comments
0
Likes
24
Embeds 0
No embeds

No notes for slide
  • \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

    1. 1. Android Unit Test Frameworkhttp://pivotal.github.com/robolectric Follow us on twitter: @robolectric
    2. 2. Joe Moore @joem Pivotal Labs @pivotallabshttp://svy.mk/robolectric
    3. 3. DisclaimerI’m mostly a Ruby guy now
    4. 4. AgendaTesting Approaches and AlternativesHow Robolectric worksWorkshop - TDD and SetupHow to extend Robolectric
    5. 5. Agile web consulting companyRuby on Rails, Android and iOSXP, TDD, Pair ProgrammingSF, NYC, Boulder, Singapore… and Atlanta!
    6. 6. We Test Stuff Cedar BDD for iOSJsUnit
    7. 7. On to the Android!
    8. 8. java.lang.RuntimeException(“Stub!”)
    9. 9. Google stripped the classes in android.jar and replaced their method bodies with:java.lang.RuntimeException(“Stub!”)
    10. 10. 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
    11. 11. Additional Android testing challengesMany of the classes and methods are finalLack of interfacesNon public constructorsstatic methods
    12. 12. It’s Getting Better CalculonA testing DSL for Google Android
    13. 13. How have you been testing?
    14. 14. Android Testing
    15. 15. Android Testing• F@*#-it!
    16. 16. Android Testing• F@*#-it!• Integration-style: Android InstrumentationTests/Robotium
    17. 17. Android Testing• F@*#-it!• Integration-style: Android InstrumentationTests/Robotium• Library of tested POJO’s
    18. 18. Android Testing• F@*#-it!• Integration-style: Android InstrumentationTests/Robotium• Library of tested POJO’s• Mocking framework
    19. 19. Why use Robolectric?
    20. 20. 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.
    21. 21. 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!
    22. 22. vs. POJO lib approach?Test ALL your code, not just non-Androidcode -- increased test coverage.… But well-tested code libraries are still agood idea.
    23. 23. vs. POJO lib approach?Robolectric is compatible with the waymost Android developers work:putting lots of stuff in Activities vs. havingcomplex object models.
    24. 24. 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
    25. 25. Robolectric lets you:Iterate quicklyWrite black box style of testsTest behavior instead of implementationHave high test coverage
    26. 26. How does it work?Shadow ObjectsView and Resource Loading
    27. 27. How does it work? Shadow ObjectsMaybe they should have been called proxies.
    28. 28. How does it work? Shadow Objects1. Robolectric intercepts the loading of Android classes under test
    29. 29. How does it work? Shadow Objects1. Robolectric intercepts the loading of Android classes under test2. Rewrites the method bodies of Android classes (using javassist)
    30. 30. 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
    31. 31. 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
    32. 32. How does it work? Shadow Objects Shadow Button getText()myButton.getText() Button (Android) return “Okay” return “Okay” text=“Okay”
    33. 33. How does it work? Shadow Objects ShadowmyButton.getSomething() Button getSomething() Button (Android) return null; Does not implement getSomething()
    34. 34. 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
    35. 35. 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
    36. 36. How can I get started?• http://pivotal.github.com/robolectric/ index.html• http://github.com/pivotal/ RobolectricSample
    37. 37. Robolectric IDE• We are IntelliJ guys• Eclipse works, too• Maven!
    38. 38. Writing Tests
    39. 39. Writing TestsTests that reference Android need to be annotated: ... @RunWith(RobolectricTestRunner.class) public class MyActivityTest { @Test public void shouldDoWizbangFooBar() { ...
    40. 40. Writing Tests Often Robolectric is InvisibleButton pressMeButton = homeActivity.findViewById(R.id.press_me_button);assertThat((String) pressMeButton.getText(), equalTo("Tests Rock!"));
    41. 41. 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.
    42. 42. Writing Tests Talking to ShadowsShadowActivity shadowActivity = shadowOf(homeActivity);Intent startedIntent = shadowActivity.getNextStartedActivity();ShadowIntent shadowIntent = shadowOf(startedIntent);
    43. 43. 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
    44. 44. 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
    45. 45. 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));}
    46. 46. Extending Robolectric Help Robolectric cover more of Android
    47. 47. Writing Shadow• @RealObject• __constructor__• @Implements• @Implementation• Robolectric.bindAllShadowClasses()
    48. 48. 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
    49. 49. Shadow Objects @RealObject@Implements(View.class)public class ShadowView { @RealObject private View realView; private int id;...
    50. 50. 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.
    51. 51. 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
    52. 52. Shadow Objectspublic class Intent { public Intent(String action, Uri uri) { /* compiled code */ } ...}public class ShadowIntent { public void __constructor__(String action,Uri uri) { ... } ...}
    53. 53. Shadow Objects@Implements(View.class)public class ShadowView { @RealObject private View realView; private int id;...
    54. 54. Shadow Objectspublic class ShadowTextView {... @Implementation public CharSequence getText() { return text; }...
    55. 55. Shadow ObjectsRobolectric.bindAllShadowClasses() • Where shadow objects are registered into Robolectric • This is a current listing of all the shadow objects provided by Robolectric
    56. 56. Thanks! Joe Moore @joem Pivotal Labs @pivotallabshttp://svy.mk/robolectric

    ×