View
3.360
Download
5
Category
Preview:
Citation preview
Unit Testing without Robolectric
A life without RobolectricDroidcon 2016@PreusslerBerlin
Different starting slide!Who uses Robolectric?How to get rid of to harshSquare like ben an jerriesNormally not about NOT using a libraryTO understand: the future need to look into the past
1
3 years ago.....
Universal City Studios
Not terminator one2
Universal City Studios
3 years ago.....
Handsome young guyOld wise man3 years = like decadeThings changed!Revisit some of the patterns and ideas4
Back to the future...
Universal City Studios
Universal City Studios
What happened?
Universal City Studios
All the shiny new tools like gradle, AS haven not been thereHad eclipse, used ant, failed using maven, Stefan Linzner and team did a lot, more professional level of android dev7
Whats wrong with Robolectric?Thats why we preferred Robolectric over Emulatur tests in the first place
20th Century Fox
Whats wrong with Robolectric?
20th Century Fox
760msrobo3:1.: 5s 700ms (robo3: 4s 839ms)Without xm parsingWith + 1 second min!9
Whats wrong with Robolectric?
20th Century Fox
7msvs3s 524ms700 times slowerWithout xm parsing
10
Whats wrong with Robolectric?
188 tests:With: 4s 809msWithout: 1s 746ms
531 tests:With: 7s 907msWithout: 2s 704ms
20th Century Fox
Whats wrong with Robolectric?Running a single test needs to be in ms
TDD bound to test performance
We run 3000+ tests
20th Century Fox
Bottleneck: Robolectric parses all your xml
13
Tired of issues like java.lang.NullPointerExceptionat org.robolectric.manifest.MetaData.init(MetaData.java:55)at org.robolectric.manifest.AndroidManifest.initMetaData(AndroidManifest.java:377)....?
Dont spent more time fixing your test setup than fixing your app
Sleepy by Tomas; flickr.com/photos/tma/2438467223; CC 2.0
Robolectric was very flaky in the pastC 2.014
Whats wrong with Robolectric?Developers used too much magicforgot what unit test should be
Your tests rely on correct 3rd party implementation
Tests itself became flaky
Android todayNew developers follow MV* patternsCode is designed to be testableNo need for Robolectric
Older projects were made with Robolectric
Projects not designed to be testable have often need for Robolectric
Older android devs hardly test anything ;)
16
Welcome to Robolectric withdrawalDay care:You have small unitsStart removing @RunWith(RobolectricTestrunner.class) and we treat the few remaining ambulantLong term care:You have large unitsUse lots of magicMama will keep baby cozy and warm... by Oreste Messina; flickr.com/photos/oremessina/17338964228; CC 2.0
Now you know why bad for you! Will help you getting off that drug!
17
Before:Robolectric.buildActivity(MyActivity.class).start().get()
Now:New MyActivity().onStart()
Welcome to Robolectric withdrawalroom to wait by Several seconds; CC 2.0; flickr.com/photos/severalseconds/16549471571; CC 2.0
There is no code that will run! mockableJar leaves everything empty!
18
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
therefore findViewById wont work unless you do it
Spy will run code but then change the result19
What about views?assertTrue( myview.getVisibility() == View.VISIBLE)
What are we actually testing here?Robolectrics View implementation!Whats the default value?Dont test what you dont own!verify(myview).setVisibility(View.VISIBLE))
Wrong side! by Jrmy Lelivre; flickr.com/photos/jrmllvr/10887774436; CC 2.0
Check behavior not states on 3rd partyBoundaries as big wall, trueman show20
What about Butterknife?Couldnt 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
21
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");
@Testpublic 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");
@Testpublic 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();}
Reading & writing are 2 seperate things!Add nomoreInteraction24
Testing Parcelation (Alternative)Tip 1: move your models AutoParcelNo need for parcelation tests anymorehttps://github.com/frankiesardo/auto-parcel
Tip 2: move parcelation code to Parcelerhttps://github.com/johncarl81/parceler
Parcels by delgrosso; flickr.com/photos/delgrossodotcom/2553424895; CC 2.0
25
Testing Intent building (Before)@Testpublic 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!
We are testing the wrong thing here: we are testing if we can get out not if something was written into the activiy! We are also testing if deal can be parceled and unparcelled.... This unit is too big(We leave our boundaries and then get in on a different place)
26
Testing Intent building (After)@Testpublic void should_create_intent () {IntentFactory.instance = mockIntentFactory();
Intent intent = MyActivity.create(mock(Context.class), deal);verify(intent).putExtra(DEAL", deal);}
@Testpublic void should_create_intent () {IntentFactory.instance = mockIntentFactory();
Intent intent = MyActivity.create(mock(Context.class), deal);verify(intent).putExtra(DEAL", deal);}
Important here implemet equals!27
Testing Intent building (After)class IntentFactory {
public static IntentFactory instance = new IntentFactory();
Intent create(Context ctx, Class
Recommended