Unit testing without Robolectric, Droidcon Berlin 2016

download Unit testing without Robolectric, Droidcon Berlin 2016

If you can't read please download the document

Transcript of Unit testing without Robolectric, Droidcon Berlin 2016

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