Unit testing on Android (Droidcon Dubai 2015)

44
Unit Tes)ng on Android Danny Preussler GROUPON DroidCon Dubai test (c) DaveBleasdale, CC by 2.0, www.flickr.com/photos/sidelong/246816211

Transcript of Unit testing on Android (Droidcon Dubai 2015)

Page 1: Unit testing on Android (Droidcon Dubai 2015)

Unit  Tes)ng  on  Android  Danny  Preussler  

GROUPON  DroidCon  Dubai  

test  (c)  DaveBleasdale,  CC  by  2.0,  www.flickr.com/photos/sidelong/246816211  

Page 2: Unit testing on Android (Droidcon Dubai 2015)

Groupon  is  the  global    leader  in  local  commerce,  

making it easy for people around the world to search !and discover great businesses at unbeatable prices.

Source: Internal data,, March 2014

WORLDWIDE!

260M+ subscribers 53.9M active customers 500+ markets 900M+ deals sold

2

$5B+ in annual billings 12,000+ global employees

Page 3: Unit testing on Android (Droidcon Dubai 2015)

Leading  the  way  in  mobile  commerce  

Our mobile app is available in 43 countries.

Groupon’s vibrant mobile marketplace connects!consumers with their local economy

3  Sources: Internal Data; iTunes ranking for US stores available here - https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewFeature?id=500873243&mt=8&v0=www-itunes25Bcountdown-appstore

Nearly 110 million people worldwide have downloaded our mobile app at the end of Q4 2014.

One of the 25 most downloaded free apps of all time

More than 50% of our Global transactions were completed on a mobile device by the end of Q4 2014

Page 4: Unit testing on Android (Droidcon Dubai 2015)

About Me? •  Groupon Berlin

•  Groupon Merchant App •  Unit Test enthusiast

Page 5: Unit testing on Android (Droidcon Dubai 2015)

What  people  say  about  unit  tes0ng  

•  Slows  you  down  

•  I  know  my  code    is  working!  

•  Only  have  UI  Code  

Day  27/365  -­‐  Imagina)on..  by  Caden  Crawford,  CC  by  2.0,  flickr.com/photos/cadencrawford/8422302030  

Page 6: Unit testing on Android (Droidcon Dubai 2015)

What is a Unit Test?

•  Small  Opposite  of  an  end-­‐to-­‐end-­‐test  test  the  smallest  unit  possible  

•  You  should  have  LOTS  of  them  

•  Fast!!!!  

container  by  www.GlynLowe.com,  CC  by  2.0,  flickr.com/photos/glynlowe/10921728045  

Page 7: Unit testing on Android (Droidcon Dubai 2015)

Why  Unit  test?    •  Documents  behaviour    

•  Refactoring  not  possible    without!    

•  Gives  trust    

•  Only  slows  down    if  you  don‘t  have  )me    for  quality  code  and  tes)ng  anyway     Da

y  27/365  -­‐  Im

agina)

on..  by  Caden

 Crawford,  CC  by  2.0,    

flickr.c

om/pho

tos/cade

ncrawford/842

2302

030  

Page 8: Unit testing on Android (Droidcon Dubai 2015)

Why  Unit  test?    

Code  without  Test  =  Legacy  code    

Only  Bad  Code  is  untestable!    

Day  27/365  -­‐  Im

agina)

on..  by  Caden

 Crawford,  CC  by  2.0,    

flickr.c

om/pho

tos/cade

ncrawford/842

2302

030  

Page 9: Unit testing on Android (Droidcon Dubai 2015)

SOLID FOUNDATION

Flughafen Berlin-Brandenburg, Blick in die Abflughalle by Muns CC BY 3.0 http://commons.wikimedia.org/wiki/File:120513-BER-innen.JPG

Page 10: Unit testing on Android (Droidcon Dubai 2015)

App development reality

Tidy garage by Bryn Pinzgauer CC 2.0 http://www.flickr.com/photos/12394349@N06/4492572621/in/photostream/

Page 11: Unit testing on Android (Droidcon Dubai 2015)

Pure JUnit?

java.lang.RuntimeException: Stub!

Android Firewall by Uncalno, CC BY 2.0 flickr.com/photos/uncalno/8538679708

Page 12: Unit testing on Android (Droidcon Dubai 2015)

Robolectric

New Android Unit Testing

Lost  Horizons  -­‐  Light  by  Simon  &  His  Camera,  CC  by  2.0  flickr.com/photos/simon__syon/14842606832  

Page 13: Unit testing on Android (Droidcon Dubai 2015)

New Android Unit Testing  

•  still experimental •  hdp://tools.android.com/tech-­‐docs/unit-­‐tes)ng-­‐support  

•  Project  structure:          src/main/java/Foo.java          src/test/java/FooTest.java

•  gradle:  android { testOptions {     unitTests.returnDefaultValues = true }

Lost  Horizons  -­‐  Light  by  Simon  &  His  Camera,  CC  by  2.0  flickr.com/photos/simon__syon/14842606832  

Page 14: Unit testing on Android (Droidcon Dubai 2015)

What  to  test?  

Start  your  engine  by  Norlando  Pobre,  CC  by  2.0,  flickr.com/photos/npobre/2601582256  

Page 15: Unit testing on Android (Droidcon Dubai 2015)

Great Wall of China (IV) by isawnyu. CC 2.0 http://www.flickr.com/photos/isawnyu/7183821643/in/photostream/

Separate Java and Android Code?

Page 16: Unit testing on Android (Droidcon Dubai 2015)

Great Wall of China (IV) by isawnyu. CC 2.0 http://www.flickr.com/photos/isawnyu/7183821643/in/photostream/

Separate Java and Android Code?

Android is not Java+UI Intent, Bundle, SparseArray, Uri.. not fancy device classes! You will never reuse this on another Java platform, stop pretending! Context everywhere Recreate the System? (interface UI {...} ?)

Page 17: Unit testing on Android (Droidcon Dubai 2015)

You  can  test  everything!  

Typing  the  universe  by  Feliciano  Guimarães,  CC  by  2.0,  flickr.com/photos/jsome1/6097841770  

Page 18: Unit testing on Android (Droidcon Dubai 2015)

„Mock“???  

Martin Fowler: „test-doubles ... pre-programmed with

expectations “

Typing  the  universe  by  Feliciano  Guimarães,  CC  by  2.0,  flickr.com/photos/jsome1/6097841770  

Page 19: Unit testing on Android (Droidcon Dubai 2015)

Typing  the  universe  by  Feliciano  Guimarães,  CC  by  2.0,  flickr.com/photos/jsome1/6097841770  

Mock  

TelephonyManager mgr = mock(TelephonyManager.class); when(mgr.getDeviceId()) .thenReturn("123456");

...  

Page 20: Unit testing on Android (Droidcon Dubai 2015)

Spy  

MyPreferences pref = spy(new MyPreferences(context));

… verify(pref).saveTitle(same(title)); verify(pref).savePersonalData(anyString());  

 

She  spy  by  Kangrex,  CC  by  2.0;  flickr.com/photos/kangrex/3012574701  

Page 21: Unit testing on Android (Droidcon Dubai 2015)

Building blocks of a Test  public class AndroidAccountsTest { AccountManager manager; AndroidAccounts tested;   @Before public void setup() {...} @Test public void should_get_token() { when(manager.peekAuthToken(....)).thenReturn("token"); String token = tested.getCurrentToken(...)

assertEquals("token", token); } }

swivel-­‐sno

t  by  Linu

s  Boh

man,  CC  2.0,  flickr.com

/pho

tos/bo

hman/160

6290

1379

 

Page 22: Unit testing on Android (Droidcon Dubai 2015)

Easy...  •  Test  u)lity  classes    

•  Test  JSON  parsing    

•  Test  API  layer    

Duplo  Pac-­‐Man  by  Dan  Diemer,  CC  by  2.0,  flickr.com/photos/diemer/192740446  

Page 23: Unit testing on Android (Droidcon Dubai 2015)

Gson gson = GsonFactory.getGson(); @Test public void should_parse_json_data() { String values = inputStreamToString(„auth.json")); AuthRslt rslt = gson.fromJson(values, AuthRslt.class); assertEquals("AQAAAABwgQ2vVzk-KjiEA3“, result.getAccessToken()); }

Easy...  

Duplo  Pac-­‐Man  by  Dan  Diemer,  CC  by  2.0,  flickr.com/photos/diemer/192740446  

Page 24: Unit testing on Android (Droidcon Dubai 2015)

Easy  when  you  do  it  right  

•  Test  user  interac)on  (click  etc)  

•  Test  Fragments  and  Ac)vi)es  

 

Lego  small  car.  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6805370739  

Page 25: Unit testing on Android (Droidcon Dubai 2015)

class NavFragment extends InjectedFragment { Interactor interactor; @OnClick(R.id.nav_button_checkout) public void onClickCheckout() { interactor.moveToCheckout( getActivity()); } }

User  interac)on  Lego  small  car.  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6805370739  

Test  for  this  is  trivial!  

Page 26: Unit testing on Android (Droidcon Dubai 2015)

Screen  changes  

@Test public void should_do_transaction() { TransactionUtil transactionsUtil = mock(TransactionUtil.class), tested.showPaymentMethods( transactionsUtil, mock(Purchase.class)); verify(transactionsUtil) .addAllowingStateLoss( any(FragmentManager.class),

eq(android.R.id.content), isA(PaymentFragment.class)); }

Lego  small  car.  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6805370739  

Page 27: Unit testing on Android (Droidcon Dubai 2015)

Screen  changes  Lego  small  car.  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6805370739  

•  Robolectric  offers  FragmentTranscta)ons  and  life  cycle  method:  

•  Robolectric .buildActivity( Activity.class) .attach() .create().....

•  Careful,  feature  flaky  

Page 28: Unit testing on Android (Droidcon Dubai 2015)

Screen  changes  Lego  small  car.  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6805370739  

•  Easier:   Field field = Fragment.class.getDeclaredField("mActivity"); field.setAccessible(true); field.set(fragmentInstance, mock(Activity.class);

•  You  might  need  also  to  mock  getResources()

Page 29: Unit testing on Android (Droidcon Dubai 2015)

Harder  but  possible  

•  Test  UI  code    

LEGO  10179  Ul)mate  Collector's  Millenium  Falcon™  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6966161598  

Page 30: Unit testing on Android (Droidcon Dubai 2015)

Test  UI  code  public class BorderPainterTest { Canvas canvas = mock(Canvas.class); Circle circle = mock(Circle.class); BorderPainter tested = new BorderPainter(); @Test public void should_draw_two_circles() { ... tested.drawBorder(new RectF(), canvas, circle); InOrder inOrder = inOrder(canvas); inOrder.verify(canvas).drawCircle(

anyFloat(), anyFloat(), eq(10f), any(Paint.class)); inOrder.verify(canvas).drawCircle(

anyFloat(), anyFloat(), eq(20f), any(Paint.class)); } }

LEGO  10179  Ul)mate  Collector's  Millenium  Falcon™  by  Do-­‐Hyun  Kim,  CC  by  2.0,  flickr.com/photos/s)ckkim/6966161598  

Page 31: Unit testing on Android (Droidcon Dubai 2015)

Wri)ng  testable  code...  

•  Clean  Code  

•  Separa)on    of  Concerns  

Manual  Inside  by  Masked  Builder,  CC  by  2.0,  flickr.com/photos/masked-­‐builder/8517238602  

Page 32: Unit testing on Android (Droidcon Dubai 2015)

Dependency  Injec)on  helps  

•  Don‘t  create  dependencies  yourself  

•  Invert  Control!    

•  Inject  them!  

construct  by  Len  Madhews,  CC  by  2.0;  flickr.com/photos/mythoto/16412713709  Syringe  with  Green  Liquid  by  Andres  Rueda,  CC  by  2.0;  lickr.com/photos/andresrueda/16558374828    

Page 33: Unit testing on Android (Droidcon Dubai 2015)

If  it‘s  hard  to  test...  

•  Class  is  too  large  •  Class  is  doing  too  many  things  •  Class  knows  too  many  things  

��Modified  condi)on/decision  coverage  for  cri)cal  souware  tes)ng  by  Nguyen  Hung  Vu,  CC  by  2.0,  www.flickr.com/photos/vuhung/14621502361  

Page 34: Unit testing on Android (Droidcon Dubai 2015)

Make  it  fail!  Apple  M

ini  DisplayPort  adapter  FAIL  by  David  Joyce,  CC  by  2.0,  flickr.com

/photos/deapeajay/2969264395  

Page 35: Unit testing on Android (Droidcon Dubai 2015)

1  method  =  1  test?  

•  Test  all  cases,  else  you  might  miss  sth  

•  one  method  should  have  mul)ple  test    (although  coverage  already  reached  with  first)  

•  Don‘t  be  super  strict  on  units,    some)mes  end  to  end  might  make  sense  i.e.  json  parsing  into  models  with  full  Json  

 

Page 36: Unit testing on Android (Droidcon Dubai 2015)

Coverage?  

• You  should  Measure    

• Mo)vates!  

• Don‘t  trust  too  much  into  it  

Page 37: Unit testing on Android (Droidcon Dubai 2015)

When  to  use  Robolectric  

•  Parcel  Tests  •  Arguments/Bundle  Tests  •  Resource  loading  Tests  

Page 38: Unit testing on Android (Droidcon Dubai 2015)

Parcel  Tests  with  Robolectric  @RunWith(RobolectricTestRunner.class)  public  class  UserTest  {          Parcel  parcel  =  Parcel.obtain();          User  tested  =  new  User("123",  "456");            @Test          public  void  check_parcel_implementa)on()  {                  tested.writeToParcel(parcel,  0);                  parcel.setDataPosi)on(0);                  User  out  =  User.CREATOR.createFromParcel(parcel);                  assertEquals("123",  out.getUser());                  assertEquals("456",  out.getPassword());          }  

Page 39: Unit testing on Android (Droidcon Dubai 2015)

Resource  Tests  with  Robolectric  

@Test  @Config(qualifiers  =  "en")  public  void  getTotalAuerTaxLong()  {          assertEquals(      "$10.00  Due“,  

             tested.getTotalAuerTaxLong(1000));  }    

Page 40: Unit testing on Android (Droidcon Dubai 2015)

Layout  tests  with  Robolectric  @Test public void checkPhoneNumberIsHidden() {

MyActivity activity = new MyActivity(); activity.onCreate(); TextView tv = (TextView) activity.findViewById(R.id.callText); assertEquals(View.GONE, tv.getVisibility());

}

Page 41: Unit testing on Android (Droidcon Dubai 2015)

Dead  End  -­‐  mid  by  bennylin0724,  CC  BY  2.0  flickr.com/photos/benny_lin/191393604  

Page 42: Unit testing on Android (Droidcon Dubai 2015)

Test  all  the  Things!  

Start  your  engine  by  Norlando  Pobre,  CC  by  2.0,  flickr.com/photos/npobre/2601582256  

Page 43: Unit testing on Android (Droidcon Dubai 2015)

THANK  YOU  Danny  Preussler  

GROUPON    Berlin  

 

[email protected]    

Page 44: Unit testing on Android (Droidcon Dubai 2015)

github.com/groupon engineering.groupon.com

Michael  Burton,  Roboguice  

Carlos  Sessa,  50  Android  hacks  

David  van  der  Bokke,  RoboRemote  

David  Willson,  Odo  

….  

Stephane  Nicolas,  RoboSpice  

Par)al  Supermen,  juliegomoll,  CC  by  2.0,  flickr.com/photos/juliegomoll/1352843346