SlideShare a Scribd company logo
1 of 60
A life without
Robolectric
Droidcon 2016
@PreusslerBerlin
3 years ago.....
©UniversalCityStudios
©UniversalCityStudios
3 years ago.....
Back to the future...
©UniversalCityStudios
©UniversalCityStudios
What happened?
©UniversalCityStudios
What’s wrong with Robolectric?
That‘s why we preferred
Robolectric over Emulatur tests
in the first place
©20thCenturyFox
What’s wrong with Robolectric?
©20thCenturyFox
What’s wrong with Robolectric?
©20thCenturyFox
What’s wrong with Robolectric?
• 188 tests:
• With: 4s 809ms
• Without: 1s 746ms
• 531 tests:
• With: 7s 907ms
• Without: 2s 704ms
©20thCenturyFox
What’s wrong with Robolectric?
• Running a single test needs to
be in ms
• TDD bound to test
performance
• We run 3000+ tests
©20thCenturyFox
Tired of issues like
java.lang.NullPointerException
at
org.robolectric.manifest.MetaData.
init(MetaData.java:55)
at
org.robolectric.manifest.AndroidMa
nifest.initMetaData(AndroidManifes
t.java:377)....
?
Don’t spent more time fixing
your test setup
than fixing your app
Sleepy by Tomas; flickr.com/photos/tma/2438467223; CC 2.0
What’s wrong with Robolectric?
• Developers used too much magic
forgot what unit test should be
• Your tests rely on correct 3rd party implementation
• Tests itself became flaky
Android today
• New developers follow MV* patterns
Code is designed to be testable
No need for Robolectric
• Older projects were made with Robolectric
• Projects not designed to be testable have often need for Robolectric
Welcome to Robolectric withdrawal
Day care:
• You have small units
Start removing
@RunWith(RobolectricTestrunner.class)
and we treat the few remaining
ambulant
Long term care:
• You have large units
• Use lots of magic
Mama will keep baby cozy and warm... by Oreste Messina; flickr.com/photos/oremessina/17338964228; CC 2.0
• Before:
Robolectric.buildActivity(
MyActivity.class).start().get()
• Now:
New MyActivity().onStart()
Welcome to Robolectric withdrawal
room to wait by Several seconds; CC 2.0; flickr.com/photos/severalseconds/16549471571; CC 2.0
What about views?
• No one will parse your xml for you!
• when(activity.findViewById(R.id.toolbar))
.thenReturn(mock(Toolbar.class);
• What if class under test?
Spy it:
tested = spy(tested);
DIY Compost Bin: Assembly by WFIU Public Radio; flickr.com/photos/wfiupublicradio/5561442658; CC 2.0
What about views?
assertTrue(
myview.getVisibility() == View.VISIBLE)
What are we actually testing here?
Robolectrics View implementation!
What‘s the default value?
Don‘t test what you don‘t own!
verify(myview).setVisibility(View.VISIBLE))
Wrongside!byJérémyLelièvre;flickr.com/photos/jrmllvr/10887774436;CC2.0
What about Butterknife?
Couldn‘t be more easy:
fields are package protected
@BindView(R.id.title)
TextView title;
Just set them:
tested.title =
mock(TextView.class)
Butter by Joanna Bourne flickr.com/photos/66992990@N00/4819375090; CC 2.0
Testing Parcelation (Before)
@RunWith(RobolectricTestRunner.class)
public class UserTest {
Parcel parcel = Parcel.obtain();
User tested = new User("123", "456");
@Test
public void check_parcel_implementation() {
tested.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
User out = User.CREATOR.createFromParcel(parcel);
assertEquals("123", out.getUser());
assertEquals("456", out.getPassword());
}
Testing Parcelation (After)
Parcel parcel = mock(Parcel.class);
User tested = new User("123", "456");
@Test
public void should_read_from_parcel() {
when(parcel.readString()).thenReturn("123", "456");
User out = User.CREATOR.createFromParcel(parcel);
assertEquals("123", out.getUser());
assertEquals("456", out.getPassword());
}
Testing Parcelation (After)
Parcel parcel = mock(Parcel.class);
User tested = new User("123", "456");
@Test
public void should_write_to_parcel() {
tested.writeToParcel(parcel, 0);
InOrder verifier = inOrder(parcel);
verifier.verify(parcel).writeString("123");
verifier.verify(parcel).writeString("456");
verifier.verifyNoMoreInteractions();
}
Testing Parcelation (Alternative)
Tip 1: move your models AutoParcel
• No need for parcelation tests anymore
• https://github.com/frankiesardo/auto-parcel
Tip 2: move parcelation code to Parceler
• https://github.com/johncarl81/parceler
Parcels by delgrosso; flickr.com/photos/delgrossodotcom/2553424895; CC 2.0
Testing Intent building (Before)
@Test
public void should_create_intent() {
Intent intent = MyActivity.create(
mock(Context.class), deal);
assertEquals(
deal,
intent.getParcelableExtra(“DEAL“));
}
What are we actually testing here?
Robolectrics Intent implementation!
Dont test what you dont own!
Testing Intent building (After)
@Test
public void should_create_intent () {
IntentFactory.instance =
mockIntentFactory();
Intent intent = MyActivity.create(
mock(Context.class), deal);
verify(intent).putExtra(“DEAL", deal);}
@Test
public void should_create_intent () {
IntentFactory.instance =
mockIntentFactory();
Intent intent = MyActivity.create(
mock(Context.class), deal);
verify(intent).putExtra(“DEAL", deal);}
Testing Intent building (After)
class IntentFactory {
public static IntentFactory instance = new IntentFactory();
Intent create(Context ctx, Class<? extends Context> clazz){
return new Intent(ctx, clazz);
}
}
 Call from @After
public static void reset() {
instance = new IntentFactory();
}
Testing Intent building (after)
• Scared of the public instance
?
• Could be private but then
need setter or reflection
• Whom are you afraid of?
Dr. EVIL (Doctor Malito en Austin Powers) by Hersson Piratoba;
Testing intent building (after)
Do you know the rule about
encapsulation and tests?
Uh, no. What rule is that?
Tests trump Encapsulation.
What does that mean?
That means that tests win.
No test can be denied access to a variable
simply to maintain encapsulation.
Uncle Bob
https://blog.8thlight.com/uncle-bob/2015/06/30/the-little-
singleton.html
Why so serious? by SYD, MsSaraKelly;
flickr.com/photos/mssarakelly/14403017054, CC 2.0
If you still dont like it..
package protected and move mocking to a class in test in same package:
public class IntentFactoryMock {
public static void mockFactory(Intent intent) {
IntentFactory.instance = mockIntentFactory(intent);
}
public static void reset() {
IntentFactory.instance = new IntentFactory();
}
private static IntentFactory mockIntentFactory(Intent intent) {
IntentFactory factory = mock(IntentFactory.class);
when(factory.create()).thenReturn(intent);
Testing intent building (alternative)
• Check out Dart and Henson:
https://medium.com/groupon-
eng/better-android-intents-with-dart-
henson-1ca91793944b#.c7agm3ikh
Navigation
FragmentManager fragmentManager = mock(FragmentManager.class);
when(fragmentManager.beginTransaction()).thenReturn(transaction);
when(transaction.replace(anyInt(),
any(Fragment.class))).thenReturn(transaction);
when(transaction.replace(anyInt(), any(Fragment.class),
anyString())).thenReturn(transaction);
when(transaction.remove(any(Fragment.class))).thenReturn(transaction);
when(transaction.addToBackStack(anyString())).thenReturn(transaction);
when(transaction.add(anyInt(),
any(Fragment.class))).thenReturn(transaction);
when(transaction.add(anyInt(), any(Fragment.class),
anyString())).thenReturn(transaction);
when(transaction.setCustomAnimations(anyInt(),
anyInt())).thenReturn(transaction);
when(transaction.setCustomAnimations(anyInt(), anyInt(), anyInt(),
anyInt())).thenReturn(transaction);
Mocking fragment transactions sucks
Navigation by Marcus Ramberg; flickr.com/photos/marcusramberg/71281972; CC 2.0
Navigation by Marcus Ramberg; flickr.com/photos/marcusramberg/71281972; CC 2.0
Navigation
• Wrap navigation into a component:
@Inject
public Interactor(FragmentTransactionsUtil util)
{...}
util.addAllowingStateLoss(
getFragmengManager(), R.id.content,
MyFragment.create());
Dagger, Butterknife & co.
• Don‘t use Dagger in unit tests!
• Call the constructor yourself
Constructor injection is the only one you should use
• For activites, services, fragment with @Inject fields:
Set the instances directly, package protected!
• KISS: Keep it simple stupid!
Dagger, Butterknife & co.
• Never use Dagger.inject() and co directly!
• Wrap it
• Replace them in tests!
public final class Dependencies {
private static Injector instance = new DaggerInjector();
private static ViewBinder viewBinder = new ViewBinderWithButterknife();
private static ExtraBinder extraBinder = new ExtraBinderWithDart();
public static void bind(Activity activity) {...}
...
Butter your tests...
• Introducing Diacetyl
• ... is added to some foods to impart
its buttery flavor (wikipedia)
• It adds artifical butter flavor to your
Butterknife in test environments.
Pam Cooking Spray, Butter by Mike Mozart; flickr.com/photos/jeepersmedia/15203456322; CC 2.0
Butter your tests...
class MyButterKnifeActivity {
@Bind TextView textView;
@Bind EditText editText;
...
class MyButterKnifeActivityTest {
@Test
public void test() {
MyButterKnifeActivtiy tested = new
MyButterKnifeActivtiy();
Diacetyl.butterForTests(tested);
Pam Cooking Spray, Butter by Mike Mozart; flickr.com/photos/jeepersmedia/15203456322; CC 2.0
Butter your tests...
https://github.com/dpreussler/Diacetyl
Pam Cooking Spray, Butter by Mike Mozart; flickr.com/photos/jeepersmedia/15203456322; CC 2.0
Version checks
public boolean isRTL() {
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.JELLY_BEAN_MR1) {
return resources.getConfiguration()
.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
return false;
}
Version checks (Before)
@Test
@Config(reportSdk = 16)
public void returns_false_on_pre_jellybeans() {
Resources resources =
Robolectric.buildActivity(Activity.class)
.get().getResources();
RTLUtil tested = new RTLUtil(resources);
assertFalse(tested.isRTL());
}
Version checks
• Use reflection?
*github.com/dpreussler/SuperReflect
Reflect.on(
Build.VERSION.class)
.set("SDK_INT", 14);
Better:
wrap all the things!
Reflection by Anderson Mancini; flickr.com/photos/ektogamat/3052020494; CC 2.0
Version checks (After)
public boolean isRTL() {
if (AndroidVersions.isMinJellyBeanMR1()) {
return resources
.getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_RTL;
}
return false;
}
Version checks
@Test
public void returns_false_on_pre_jelly_beans() {
AndroidVersions.VERSION = 16;
Resources resources = mockResources();
RTLUtil tested = new RTLUtil(resources);
assertFalse(tested.isRTL());
verifyZeroInteractions(resources);
}
Version checks
public final class AndroidVersions {
public static int VERSION = Build.VERSION.SDK_INT;
public static boolean isMinJellyBean() {
return VERSION >= Build.VERSION_CODES.JELLY_BEAN;
}
...
}
 Call from @After
public static void reset() {
VERSION = Build.VERSION.SDK_INT;
}
Testing asynchronicity
• Robolectric.flushBackgroundThreadScheduler()
• ShadowApplication.runBackgroundTasks();
•This is wrong!
• Just override runOnUiThread() instead!
Rollercoaster by Eric; flickr.com/photos/eric-omba/481762682; CC 2.0
Testing asynchronicity (Before)
MyActivity activity =
Robolectric.buildActivity(MyActivity.class).get();
activity.doThingInBackground();
Robolectric.getForegroundThreadScheduler()
.advanceToNextPostedRunnable();
// check what happened in runnable
Testing asynchronicity (After)
MyActivity activity = spy(new MyActivity());
ArgumentCaptor<Runnable> captor =
ArgumentCaptor.forClass(Runnable.class);
activity.doThingInBackground();
verify(activity).runOnUiThread(captor.capture());
captor.getValue().run();
... Tip: split into 2 tests:
• verify(activity).runOnUiThread(anyRunnable())
• and the captor one that does the action
Testing asynchronicity
„Always wrap the system clock,
so it can be easily substituted
for testing“
(Martin Fowler)
http://martinfowler.com/articles/nonDeterminism.html#Time
Rollercoaster by Eric; flickr.com/photos/eric-omba/481762682; CC 2.0
Problem: Libraries
• Support libraries
• Third party libraries
• Implementation not
empty,
Run real code on tests
Delivery by Bill; flickr.com/photos/34639780@N07/16480925469; CC 2.0
Problem: Libraries
Example:
• Fragment:onStart
is empty
• SupportFragment:onStart
actually does things
Delivery by Bill; flickr.com/photos/34639780@N07/16480925469; CC 2.0
Problem: Libraries
• Needs more mocking
• Might need Reflection work
• Tricky on constructors
i.e. custom views extends
„empty“ android views
Delivery by Bill; flickr.com/photos/34639780@N07/16480925469; CC 2.0
Libraries (Reflection needed)
CredentialsApi realApi = Auth.CredentialsApi;
CredentialsApi apiMock = mock(CredentialsApi.class);
SuperReflect.on(Auth.class).set("CredentialsApi", apiMock);
...
tested.onConnected(mockBundle());
verify(apiMock).request(
any(GoogleApiClient.class), any(CredentialRequest.class));
@After
public void tearDown() {
SuperReflect.on(Auth.class).set("CredentialsApi", realApi);
}
Write it nicer
• mockView() instead of mock(View.class)
...
• mockEditText(„test“)that implements Editable
• mockFragmentTransaction() that returns self while building
• mockRecyclerView() that remembers adapter
https://github.com/dpreussler/mockitoid
rainbow revisited by Bill Rosgen; flickr.com/photos/wrosgen/4706169184; CC 2.0
Write it nicer
• anyActivity() instead of any(Activity.class)
• anyContext()...
• anyView()...
https://github.com/dpreussler/mockitoid
rainbow revisited by Bill Rosgen; flickr.com/photos/wrosgen/4706169184; CC 2.0
Gradually stop your addiction
Subscription: Unmock
Decide in gradle which classes
you still need from Robolectric
https://github.com/bjoernQ/unmock-plugin
Any reasons to stick to Robolectric?
“I need to test lots of UI”
Test with mocks!
“My tests are testing a complete flow”
Your tests are too big
“My tests depend on resources”
Integration test? Move to Espresso?
Any reasons to stick to Robolectric?
“I want to test my SqlLiteOpenhelper with a real database?”
Wrap SqlLiteopenHelper!
Assert Query Strings
(Use a java version of SQLlite if you real queries)
No reason!
And often smell for bad code design! Fix the
code not the test!
Groupon is Mobile
One of worlds most popular apps
> 50 Mio android downloads
Unit testing by developers
> 2000 unit test for Consumer app
> 3000 unit tests for Merchant app
Automation by QA engineers
RoboRemote for Consumer app
Appium for Merchant app
Danny Preussler
@PreusslerBerlin
ThankYoubyNateGrigg;
www.flickr.com/photos/nateone/3768979925,CC2.0

More Related Content

What's hot

Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
julien.ponge
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011
Anton Arhipov
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
julien.ponge
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
Tomek Kaczanowski
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
Droidcon Berlin
 
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingRiga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Anton Arhipov
 

What's hot (20)

Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
 
GMock framework
GMock frameworkGMock framework
GMock framework
 
Redux for ReactJS Programmers
Redux for ReactJS ProgrammersRedux for ReactJS Programmers
Redux for ReactJS Programmers
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011
 
droidparts
droidpartsdroidparts
droidparts
 
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingJEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
 
Introduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicoxIntroduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicox
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
 
Java 7 LavaJUG
Java 7 LavaJUGJava 7 LavaJUG
Java 7 LavaJUG
 
JS and patterns
JS and patternsJS and patterns
JS and patterns
 
Android & Kotlin - The code awakens #01
Android & Kotlin - The code awakens #01Android & Kotlin - The code awakens #01
Android & Kotlin - The code awakens #01
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
 
Using the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentUsing the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM Development
 
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingRiga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
 
groovy & grails - lecture 7
groovy & grails - lecture 7groovy & grails - lecture 7
groovy & grails - lecture 7
 

Viewers also liked

Viewers also liked (14)

Little Helpers for Android Development with Kotlin
Little Helpers for Android Development with KotlinLittle Helpers for Android Development with Kotlin
Little Helpers for Android Development with Kotlin
 
Add ClassyShark to your Android toolbox
Add ClassyShark to your Android toolboxAdd ClassyShark to your Android toolbox
Add ClassyShark to your Android toolbox
 
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
Bye Bye Charles, Welcome Odo, Android Meetup Berlin May 2014
 
Android Unit Testing With Robolectric
Android Unit Testing With RobolectricAndroid Unit Testing With Robolectric
Android Unit Testing With Robolectric
 
The Next Step for Reactive Android Programming
The Next Step for Reactive Android ProgrammingThe Next Step for Reactive Android Programming
The Next Step for Reactive Android Programming
 
Creating Gradle Plugins - Oredev
Creating Gradle Plugins - OredevCreating Gradle Plugins - Oredev
Creating Gradle Plugins - Oredev
 
A realtime infrastructure for Android apps: Firebase may be what you need..an...
A realtime infrastructure for Android apps: Firebase may be what you need..an...A realtime infrastructure for Android apps: Firebase may be what you need..an...
A realtime infrastructure for Android apps: Firebase may be what you need..an...
 
Developing Apps for Emerging Markets
Developing Apps for Emerging MarketsDeveloping Apps for Emerging Markets
Developing Apps for Emerging Markets
 
Develop Maintainable Apps - edUiConf
Develop Maintainable Apps - edUiConfDevelop Maintainable Apps - edUiConf
Develop Maintainable Apps - edUiConf
 
Unit Testing on Android: why and how? DevFest Romania, Bucharest 2016
Unit Testing on Android: why and how? DevFest Romania, Bucharest 2016Unit Testing on Android: why and how? DevFest Romania, Bucharest 2016
Unit Testing on Android: why and how? DevFest Romania, Bucharest 2016
 
프로그래밍 대회: C++11 이야기
프로그래밍 대회: C++11 이야기프로그래밍 대회: C++11 이야기
프로그래밍 대회: C++11 이야기
 
MVVM and RxJava – the perfect mix
MVVM and RxJava – the perfect mixMVVM and RxJava – the perfect mix
MVVM and RxJava – the perfect mix
 
2016 FunctionCup 풀이
2016 FunctionCup 풀이2016 FunctionCup 풀이
2016 FunctionCup 풀이
 
Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Mastering the NDK with Android Studio 2.0 and the gradle-experimental pluginMastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
 

Similar to Unit testing without Robolectric, Droidcon Berlin 2016

Unit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, MelonUnit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
beITconference
 
谷歌 Scott-lessons learned in testability
谷歌 Scott-lessons learned in testability谷歌 Scott-lessons learned in testability
谷歌 Scott-lessons learned in testability
drewz lin
 

Similar to Unit testing without Robolectric, Droidcon Berlin 2016 (20)

Pro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScriptPro typescript.ch03.Object Orientation in TypeScript
Pro typescript.ch03.Object Orientation in TypeScript
 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloaded
 
Alexey Buzdin "Maslow's Pyramid of Android Testing"
Alexey Buzdin "Maslow's Pyramid of Android Testing"Alexey Buzdin "Maslow's Pyramid of Android Testing"
Alexey Buzdin "Maslow's Pyramid of Android Testing"
 
Testing in android
Testing in androidTesting in android
Testing in android
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
 
少し幸せになる技術
少し幸せになる技術少し幸せになる技術
少し幸せになる技術
 
Mastering Mock Objects - Advanced Unit Testing for Java
Mastering Mock Objects - Advanced Unit Testing for JavaMastering Mock Objects - Advanced Unit Testing for Java
Mastering Mock Objects - Advanced Unit Testing for Java
 
Android testing
Android testingAndroid testing
Android testing
 
Introduction to Testcontainers
Introduction to TestcontainersIntroduction to Testcontainers
Introduction to Testcontainers
 
Guide to the jungle of testing frameworks
Guide to the jungle of testing frameworksGuide to the jungle of testing frameworks
Guide to the jungle of testing frameworks
 
Testing microservices: Tools and Frameworks
Testing microservices: Tools and FrameworksTesting microservices: Tools and Frameworks
Testing microservices: Tools and Frameworks
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Java design patterns
Java design patternsJava design patterns
Java design patterns
 
droidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutinesdroidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutines
 
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, MelonUnit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
 
谷歌 Scott-lessons learned in testability
谷歌 Scott-lessons learned in testability谷歌 Scott-lessons learned in testability
谷歌 Scott-lessons learned in testability
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
 
Kotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesKotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutines
 

More from Danny Preussler

More from Danny Preussler (12)

We aint got no time - Droidcon Nairobi
We aint got no time - Droidcon NairobiWe aint got no time - Droidcon Nairobi
We aint got no time - Droidcon Nairobi
 
Test Driven Development on Android (Kotlin Kenya)
Test Driven Development on Android (Kotlin Kenya)Test Driven Development on Android (Kotlin Kenya)
Test Driven Development on Android (Kotlin Kenya)
 
TDD on android. Why and How? (Coding Serbia 2019)
TDD on android. Why and How? (Coding Serbia 2019)TDD on android. Why and How? (Coding Serbia 2019)
TDD on android. Why and How? (Coding Serbia 2019)
 
TDD on Android (Øredev 2018)
TDD on Android (Øredev 2018)TDD on Android (Øredev 2018)
TDD on Android (Øredev 2018)
 
Junit5: the next gen of testing, don't stay behind
Junit5: the next gen of testing, don't stay behindJunit5: the next gen of testing, don't stay behind
Junit5: the next gen of testing, don't stay behind
 
All around the world, localization and internationalization on Android (Droid...
All around the world, localization and internationalization on Android (Droid...All around the world, localization and internationalization on Android (Droid...
All around the world, localization and internationalization on Android (Droid...
 
(Android) Developer Survival in Multiscreen World, MobCon Sofia 2016
(Android) Developer Survival in Multiscreen World, MobCon Sofia 2016(Android) Developer Survival in Multiscreen World, MobCon Sofia 2016
(Android) Developer Survival in Multiscreen World, MobCon Sofia 2016
 
Unit testing on Android (Droidcon Dubai 2015)
Unit testing on Android (Droidcon Dubai 2015)Unit testing on Android (Droidcon Dubai 2015)
Unit testing on Android (Droidcon Dubai 2015)
 
Clean code on Android (Droidcon Dubai 2015)
Clean code on Android (Droidcon Dubai 2015)Clean code on Android (Droidcon Dubai 2015)
Clean code on Android (Droidcon Dubai 2015)
 
Abgeschottete Realität - Testen im Emulator, Mobile Testing Days 2014, Berlin
Abgeschottete Realität - Testen im Emulator, Mobile Testing Days 2014, BerlinAbgeschottete Realität - Testen im Emulator, Mobile Testing Days 2014, Berlin
Abgeschottete Realität - Testen im Emulator, Mobile Testing Days 2014, Berlin
 
Rockstar Android Testing (Mobile TechCon Munich 2014)
Rockstar Android Testing (Mobile TechCon Munich 2014)Rockstar Android Testing (Mobile TechCon Munich 2014)
Rockstar Android Testing (Mobile TechCon Munich 2014)
 
Android Code Puzzles (DroidCon Amsterdam 2012)
Android Code Puzzles (DroidCon Amsterdam 2012)Android Code Puzzles (DroidCon Amsterdam 2012)
Android Code Puzzles (DroidCon Amsterdam 2012)
 

Recently uploaded

notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
MsecMca
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
dollysharma2066
 
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
amitlee9823
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
Epec Engineered Technologies
 
Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
Neometrix_Engineering_Pvt_Ltd
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ssuser89054b
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Kandungan 087776558899
 

Recently uploaded (20)

notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
 
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
 
Work-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptxWork-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptx
 
Employee leave management system project.
Employee leave management system project.Employee leave management system project.
Employee leave management system project.
 
Design For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the startDesign For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the start
 
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performance
 
University management System project report..pdf
University management System project report..pdfUniversity management System project report..pdf
University management System project report..pdf
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
 
22-prompt engineering noted slide shown.pdf
22-prompt engineering noted slide shown.pdf22-prompt engineering noted slide shown.pdf
22-prompt engineering noted slide shown.pdf
 
Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
Water Industry Process Automation & Control Monthly - April 2024
Water Industry Process Automation & Control Monthly - April 2024Water Industry Process Automation & Control Monthly - April 2024
Water Industry Process Automation & Control Monthly - April 2024
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leap
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
 

Unit testing without Robolectric, Droidcon Berlin 2016

  • 1. A life without Robolectric Droidcon 2016 @PreusslerBerlin
  • 5. Back to the future... ©UniversalCityStudios
  • 8. What’s wrong with Robolectric? That‘s why we preferred Robolectric over Emulatur tests in the first place ©20thCenturyFox
  • 9. What’s wrong with Robolectric? ©20thCenturyFox
  • 10. What’s wrong with Robolectric? ©20thCenturyFox
  • 11.
  • 12. What’s wrong with Robolectric? • 188 tests: • With: 4s 809ms • Without: 1s 746ms • 531 tests: • With: 7s 907ms • Without: 2s 704ms ©20thCenturyFox
  • 13. What’s wrong with Robolectric? • Running a single test needs to be in ms • TDD bound to test performance • We run 3000+ tests ©20thCenturyFox
  • 14. Tired of issues like java.lang.NullPointerException at org.robolectric.manifest.MetaData. init(MetaData.java:55) at org.robolectric.manifest.AndroidMa nifest.initMetaData(AndroidManifes t.java:377).... ? Don’t spent more time fixing your test setup than fixing your app Sleepy by Tomas; flickr.com/photos/tma/2438467223; CC 2.0
  • 15. What’s wrong with Robolectric? • Developers used too much magic forgot what unit test should be • Your tests rely on correct 3rd party implementation • Tests itself became flaky
  • 16. Android today • New developers follow MV* patterns Code is designed to be testable No need for Robolectric • Older projects were made with Robolectric • Projects not designed to be testable have often need for Robolectric
  • 17. Welcome to Robolectric withdrawal Day care: • You have small units Start removing @RunWith(RobolectricTestrunner.class) and we treat the few remaining ambulant Long term care: • You have large units • Use lots of magic Mama will keep baby cozy and warm... by Oreste Messina; flickr.com/photos/oremessina/17338964228; CC 2.0
  • 18. • Before: Robolectric.buildActivity( MyActivity.class).start().get() • Now: New MyActivity().onStart() Welcome to Robolectric withdrawal room to wait by Several seconds; CC 2.0; flickr.com/photos/severalseconds/16549471571; CC 2.0
  • 19. What about views? • No one will parse your xml for you! • when(activity.findViewById(R.id.toolbar)) .thenReturn(mock(Toolbar.class); • What if class under test? Spy it: tested = spy(tested); DIY Compost Bin: Assembly by WFIU Public Radio; flickr.com/photos/wfiupublicradio/5561442658; CC 2.0
  • 20. What about views? assertTrue( myview.getVisibility() == View.VISIBLE) What are we actually testing here? Robolectrics View implementation! What‘s the default value? Don‘t test what you don‘t own! verify(myview).setVisibility(View.VISIBLE)) Wrongside!byJérémyLelièvre;flickr.com/photos/jrmllvr/10887774436;CC2.0
  • 21. What about Butterknife? Couldn‘t be more easy: fields are package protected @BindView(R.id.title) TextView title; Just set them: tested.title = mock(TextView.class) Butter by Joanna Bourne flickr.com/photos/66992990@N00/4819375090; CC 2.0
  • 22. Testing Parcelation (Before) @RunWith(RobolectricTestRunner.class) public class UserTest { Parcel parcel = Parcel.obtain(); User tested = new User("123", "456"); @Test public void check_parcel_implementation() { tested.writeToParcel(parcel, 0); parcel.setDataPosition(0); User out = User.CREATOR.createFromParcel(parcel); assertEquals("123", out.getUser()); assertEquals("456", out.getPassword()); }
  • 23. Testing Parcelation (After) Parcel parcel = mock(Parcel.class); User tested = new User("123", "456"); @Test public void should_read_from_parcel() { when(parcel.readString()).thenReturn("123", "456"); User out = User.CREATOR.createFromParcel(parcel); assertEquals("123", out.getUser()); assertEquals("456", out.getPassword()); }
  • 24. Testing Parcelation (After) Parcel parcel = mock(Parcel.class); User tested = new User("123", "456"); @Test public void should_write_to_parcel() { tested.writeToParcel(parcel, 0); InOrder verifier = inOrder(parcel); verifier.verify(parcel).writeString("123"); verifier.verify(parcel).writeString("456"); verifier.verifyNoMoreInteractions(); }
  • 25. Testing Parcelation (Alternative) Tip 1: move your models AutoParcel • No need for parcelation tests anymore • https://github.com/frankiesardo/auto-parcel Tip 2: move parcelation code to Parceler • https://github.com/johncarl81/parceler Parcels by delgrosso; flickr.com/photos/delgrossodotcom/2553424895; CC 2.0
  • 26. Testing Intent building (Before) @Test public void should_create_intent() { Intent intent = MyActivity.create( mock(Context.class), deal); assertEquals( deal, intent.getParcelableExtra(“DEAL“)); } What are we actually testing here? Robolectrics Intent implementation! Dont test what you dont own!
  • 27. Testing Intent building (After) @Test public void should_create_intent () { IntentFactory.instance = mockIntentFactory(); Intent intent = MyActivity.create( mock(Context.class), deal); verify(intent).putExtra(“DEAL", deal);} @Test public void should_create_intent () { IntentFactory.instance = mockIntentFactory(); Intent intent = MyActivity.create( mock(Context.class), deal); verify(intent).putExtra(“DEAL", deal);}
  • 28. Testing Intent building (After) class IntentFactory { public static IntentFactory instance = new IntentFactory(); Intent create(Context ctx, Class<? extends Context> clazz){ return new Intent(ctx, clazz); } }  Call from @After public static void reset() { instance = new IntentFactory(); }
  • 29. Testing Intent building (after) • Scared of the public instance ? • Could be private but then need setter or reflection • Whom are you afraid of? Dr. EVIL (Doctor Malito en Austin Powers) by Hersson Piratoba;
  • 30. Testing intent building (after) Do you know the rule about encapsulation and tests? Uh, no. What rule is that? Tests trump Encapsulation. What does that mean? That means that tests win. No test can be denied access to a variable simply to maintain encapsulation. Uncle Bob https://blog.8thlight.com/uncle-bob/2015/06/30/the-little- singleton.html Why so serious? by SYD, MsSaraKelly; flickr.com/photos/mssarakelly/14403017054, CC 2.0
  • 31. If you still dont like it.. package protected and move mocking to a class in test in same package: public class IntentFactoryMock { public static void mockFactory(Intent intent) { IntentFactory.instance = mockIntentFactory(intent); } public static void reset() { IntentFactory.instance = new IntentFactory(); } private static IntentFactory mockIntentFactory(Intent intent) { IntentFactory factory = mock(IntentFactory.class); when(factory.create()).thenReturn(intent);
  • 32. Testing intent building (alternative) • Check out Dart and Henson: https://medium.com/groupon- eng/better-android-intents-with-dart- henson-1ca91793944b#.c7agm3ikh
  • 33. Navigation FragmentManager fragmentManager = mock(FragmentManager.class); when(fragmentManager.beginTransaction()).thenReturn(transaction); when(transaction.replace(anyInt(), any(Fragment.class))).thenReturn(transaction); when(transaction.replace(anyInt(), any(Fragment.class), anyString())).thenReturn(transaction); when(transaction.remove(any(Fragment.class))).thenReturn(transaction); when(transaction.addToBackStack(anyString())).thenReturn(transaction); when(transaction.add(anyInt(), any(Fragment.class))).thenReturn(transaction); when(transaction.add(anyInt(), any(Fragment.class), anyString())).thenReturn(transaction); when(transaction.setCustomAnimations(anyInt(), anyInt())).thenReturn(transaction); when(transaction.setCustomAnimations(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(transaction); Mocking fragment transactions sucks Navigation by Marcus Ramberg; flickr.com/photos/marcusramberg/71281972; CC 2.0
  • 34. Navigation by Marcus Ramberg; flickr.com/photos/marcusramberg/71281972; CC 2.0 Navigation • Wrap navigation into a component: @Inject public Interactor(FragmentTransactionsUtil util) {...} util.addAllowingStateLoss( getFragmengManager(), R.id.content, MyFragment.create());
  • 35. Dagger, Butterknife & co. • Don‘t use Dagger in unit tests! • Call the constructor yourself Constructor injection is the only one you should use • For activites, services, fragment with @Inject fields: Set the instances directly, package protected! • KISS: Keep it simple stupid!
  • 36. Dagger, Butterknife & co. • Never use Dagger.inject() and co directly! • Wrap it • Replace them in tests! public final class Dependencies { private static Injector instance = new DaggerInjector(); private static ViewBinder viewBinder = new ViewBinderWithButterknife(); private static ExtraBinder extraBinder = new ExtraBinderWithDart(); public static void bind(Activity activity) {...} ...
  • 37. Butter your tests... • Introducing Diacetyl • ... is added to some foods to impart its buttery flavor (wikipedia) • It adds artifical butter flavor to your Butterknife in test environments. Pam Cooking Spray, Butter by Mike Mozart; flickr.com/photos/jeepersmedia/15203456322; CC 2.0
  • 38. Butter your tests... class MyButterKnifeActivity { @Bind TextView textView; @Bind EditText editText; ... class MyButterKnifeActivityTest { @Test public void test() { MyButterKnifeActivtiy tested = new MyButterKnifeActivtiy(); Diacetyl.butterForTests(tested); Pam Cooking Spray, Butter by Mike Mozart; flickr.com/photos/jeepersmedia/15203456322; CC 2.0
  • 39. Butter your tests... https://github.com/dpreussler/Diacetyl Pam Cooking Spray, Butter by Mike Mozart; flickr.com/photos/jeepersmedia/15203456322; CC 2.0
  • 40. Version checks public boolean isRTL() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { return resources.getConfiguration() .getLayoutDirection() == LAYOUT_DIRECTION_RTL; } return false; }
  • 41. Version checks (Before) @Test @Config(reportSdk = 16) public void returns_false_on_pre_jellybeans() { Resources resources = Robolectric.buildActivity(Activity.class) .get().getResources(); RTLUtil tested = new RTLUtil(resources); assertFalse(tested.isRTL()); }
  • 42. Version checks • Use reflection? *github.com/dpreussler/SuperReflect Reflect.on( Build.VERSION.class) .set("SDK_INT", 14); Better: wrap all the things! Reflection by Anderson Mancini; flickr.com/photos/ektogamat/3052020494; CC 2.0
  • 43. Version checks (After) public boolean isRTL() { if (AndroidVersions.isMinJellyBeanMR1()) { return resources .getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; } return false; }
  • 44. Version checks @Test public void returns_false_on_pre_jelly_beans() { AndroidVersions.VERSION = 16; Resources resources = mockResources(); RTLUtil tested = new RTLUtil(resources); assertFalse(tested.isRTL()); verifyZeroInteractions(resources); }
  • 45. Version checks public final class AndroidVersions { public static int VERSION = Build.VERSION.SDK_INT; public static boolean isMinJellyBean() { return VERSION >= Build.VERSION_CODES.JELLY_BEAN; } ... }  Call from @After public static void reset() { VERSION = Build.VERSION.SDK_INT; }
  • 46. Testing asynchronicity • Robolectric.flushBackgroundThreadScheduler() • ShadowApplication.runBackgroundTasks(); •This is wrong! • Just override runOnUiThread() instead! Rollercoaster by Eric; flickr.com/photos/eric-omba/481762682; CC 2.0
  • 47. Testing asynchronicity (Before) MyActivity activity = Robolectric.buildActivity(MyActivity.class).get(); activity.doThingInBackground(); Robolectric.getForegroundThreadScheduler() .advanceToNextPostedRunnable(); // check what happened in runnable
  • 48. Testing asynchronicity (After) MyActivity activity = spy(new MyActivity()); ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); activity.doThingInBackground(); verify(activity).runOnUiThread(captor.capture()); captor.getValue().run(); ... Tip: split into 2 tests: • verify(activity).runOnUiThread(anyRunnable()) • and the captor one that does the action
  • 49. Testing asynchronicity „Always wrap the system clock, so it can be easily substituted for testing“ (Martin Fowler) http://martinfowler.com/articles/nonDeterminism.html#Time Rollercoaster by Eric; flickr.com/photos/eric-omba/481762682; CC 2.0
  • 50. Problem: Libraries • Support libraries • Third party libraries • Implementation not empty, Run real code on tests Delivery by Bill; flickr.com/photos/34639780@N07/16480925469; CC 2.0
  • 51. Problem: Libraries Example: • Fragment:onStart is empty • SupportFragment:onStart actually does things Delivery by Bill; flickr.com/photos/34639780@N07/16480925469; CC 2.0
  • 52. Problem: Libraries • Needs more mocking • Might need Reflection work • Tricky on constructors i.e. custom views extends „empty“ android views Delivery by Bill; flickr.com/photos/34639780@N07/16480925469; CC 2.0
  • 53. Libraries (Reflection needed) CredentialsApi realApi = Auth.CredentialsApi; CredentialsApi apiMock = mock(CredentialsApi.class); SuperReflect.on(Auth.class).set("CredentialsApi", apiMock); ... tested.onConnected(mockBundle()); verify(apiMock).request( any(GoogleApiClient.class), any(CredentialRequest.class)); @After public void tearDown() { SuperReflect.on(Auth.class).set("CredentialsApi", realApi); }
  • 54. Write it nicer • mockView() instead of mock(View.class) ... • mockEditText(„test“)that implements Editable • mockFragmentTransaction() that returns self while building • mockRecyclerView() that remembers adapter https://github.com/dpreussler/mockitoid rainbow revisited by Bill Rosgen; flickr.com/photos/wrosgen/4706169184; CC 2.0
  • 55. Write it nicer • anyActivity() instead of any(Activity.class) • anyContext()... • anyView()... https://github.com/dpreussler/mockitoid rainbow revisited by Bill Rosgen; flickr.com/photos/wrosgen/4706169184; CC 2.0
  • 56. Gradually stop your addiction Subscription: Unmock Decide in gradle which classes you still need from Robolectric https://github.com/bjoernQ/unmock-plugin
  • 57. Any reasons to stick to Robolectric? “I need to test lots of UI” Test with mocks! “My tests are testing a complete flow” Your tests are too big “My tests depend on resources” Integration test? Move to Espresso?
  • 58. Any reasons to stick to Robolectric? “I want to test my SqlLiteOpenhelper with a real database?” Wrap SqlLiteopenHelper! Assert Query Strings (Use a java version of SQLlite if you real queries) No reason! And often smell for bad code design! Fix the code not the test!
  • 59. Groupon is Mobile One of worlds most popular apps > 50 Mio android downloads Unit testing by developers > 2000 unit test for Consumer app > 3000 unit tests for Merchant app Automation by QA engineers RoboRemote for Consumer app Appium for Merchant app