unit testing on android (droidcon dubai 2015)

Post on 16-Jul-2015

353 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Unit  Tes)ng  on  Android  Danny  Preussler  

GROUPON  DroidCon  Dubai  

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

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

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

About Me? •  Groupon Berlin

•  Groupon Merchant App •  Unit Test enthusiast

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  

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  

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  

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  

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

App development reality

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

Pure JUnit?

java.lang.RuntimeException: Stub!

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

Robolectric

New Android Unit Testing

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

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  

What  to  test?  

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

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

Separate Java and Android Code?

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 {...} ?)

You  can  test  everything!  

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

„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  

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");

...  

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  

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

 

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  

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  

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  

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!  

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  

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  

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()

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  

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  

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  

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    

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  

Make  it  fail!  Apple  M

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

/photos/deapeajay/2969264395  

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  

 

Coverage?  

• You  should  Measure    

• Mo)vates!  

• Don‘t  trust  too  much  into  it  

When  to  use  Robolectric  

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

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());          }  

Resource  Tests  with  Robolectric  

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

             tested.getTotalAuerTaxLong(1000));  }    

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());

}

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

Test  all  the  Things!  

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

THANK  YOU  Danny  Preussler  

GROUPON    Berlin  

 

dpreussler@groupon.com    

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  

top related