Slide 1

Slide 1 text

Jake Wharton Testing. Do it.

Slide 2

Slide 2 text

Robolectric & FEST Instrumentation & Spoon Dagger

Slide 3

Slide 3 text

Robolectric

Slide 4

Slide 4 text

Android APIs do not want you to test.

Slide 5

Slide 5 text

Hides the ugly with fake, stubbed, or empty implementations.

Slide 6

Slide 6 text

“Android: The Good Parts”

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

“Android: The Good Parts”

Slide 12

Slide 12 text

“Android: The Good Parts. Some okay parts too.”

Slide 13

Slide 13 text

Robolectric robolectric.org

Slide 14

Slide 14 text

FEST Android square.github.io/fest-android

Slide 15

Slide 15 text

Instrumentation

Slide 16

Slide 16 text

JUnit is small scope, low-level testing.

Slide 17

Slide 17 text

Larger scope testing that spans interaction patterns.

Slide 18

Slide 18 text

Instrumentation API Robotium UI Automator Espresso Some cucumber crap...

Slide 19

Slide 19 text

It does not matter.

Slide 20

Slide 20 text

Favor interaction over assertion

Slide 21

Slide 21 text

Go black box over IDs and view hierarchy

Slide 22

Slide 22 text

Instrumentation tests should work for you.

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Spoon square.github.io/spoon

Slide 27

Slide 27 text

Dagger

Slide 28

Slide 28 text

A fast dependency injector for Android and Java

Slide 29

Slide 29 text

Separate “do” from the “how”

Slide 30

Slide 30 text

class  TwitterClient  {    @Inject  Twitter  twitter;     }    void  show(String  user)  {        List  tweets  =  twitter.tweets(user);        for  (Tweet  tweet  :  tweets)  {            System.out.println(tweet.text);        }    }

Slide 31

Slide 31 text

@Module class  OurModule  {     }    @Provide    public  RestAdapter  provideRestAdapter()  {        return  new  RestAdapter.Builder()                .setServer("https://api.twitter.com/1/")                .build();    }    @Provide    public  Twitter  provideTwitter(RestAdapter  rest)  {        return  rest.create(Twitter.class);    } @Singleton @Singleton

Slide 32

Slide 32 text

TwitterClient  client  =  new  TwitterClient(); ObjectGraph  graph  =  ObjectGraph.create(new  OurModule()); graph.inject(client); client.show("JakeWharton"); /* Hey  UIUC  people!  Come  join  me  for  a  nerdy  chat  tomorrow  evening.  «@_chaebacca   http://t.co/SCsRFkdg» FEST  Android  v1.0.1  released  (while  at  37,000  feet!)  with  a  slew  of  new  asserts,   generics,  and  spelling  corrections.  http://t.co/JSGRoO7m @neilmctee  @robolectric  This  is  because  Build.SDK.VERSION  still  reports  '0'.  Now   that  we  are  using  real  code,  it  should  probably  return  '16' For  this  day  and  age,  it's  amazing  how  difficult  and  slow  it  is  to  move  money   around  between  banks  and  individuals. JavaWriter  -­‐  A  utility  which  aids  in  generating  Java  source  files.  https://t.co/ enypYzsW */

Slide 33

Slide 33 text

Annotation processing code generation

Slide 34

Slide 34 text

class  TwitterClient$$InjectAdapter  {    void  inject(TwitterClient  client,  Twitter  twitter)  {        client.twitter  =  twitter;    } } class  TwitterClient  {    @Inject  Twitter  twitter;        void  show(String  user)  {        List  tweets  =  twitter.tweets(user);        for  (Tweet  tweet  :  tweets)  {            System.out.println(tweet.text);        }    } }

Slide 35

Slide 35 text

class  FooApplication  extends  Application  {    private  ObjectGraph  graph;         }    @Override  public  void  onCreate()  {        super.onCreate();        graph  =  ObjectGraph.create(            new  ThisModule(),            new  ThatModule(),            new  OtherModule(this)  //  This  module  takes  the  context        );    }    public  void  inject(Object  object)  {        graph.inject(object);    }

Slide 36

Slide 36 text

class  BaseActivity  extends  Activity  {    @Override  public  void  onCreate(Bundle  saved)  {        super.onCreate(saved);                //  WARNING:  Boilerplate!        ((FooApplication)  getApplication()).inject(this);    } }

Slide 37

Slide 37 text

class  TweetsActivity  extends  BaseActivity  {    @Inject  Twitter  twitter;        @Override  public  void  onCreate(Bundle  saved)  {        super.onCreate(saved);                    } }        setContentView(R.layout.tweets_activity);        ListView  lv  =  (ListView)  findViewById(R.id.tweets_list);        final  ArrayAdapter  adapter  =  new  ArrayAdapter(/*...*/);        lv.setAdapter(adapter);        twitter.tweets("JakeWharton",  new  Callback>()  {            @Override  public  void  onSuccess(List  tweets)  {                adapter.addAll(tweets);                adapter.notifyDataSetChanged();            }        }

Slide 38

Slide 38 text

interface  Twitter  {    @GET("statuses/user_timeline.json")    List  tweets(@Named("screen_name")  String  user); } class  FakeTwitter  implements  Twitter  {    @Override  public  List  tweets(String  user)  {        return  Arrays.asList(            new  Tweet("The  quick  brown  fox"),            new  Tweet("Jumps  over  the  lazy  dog"),            new  Tweet("OMG  WTF  BBQ")        );    } }

Slide 39

Slide 39 text

@Module(overrides  =  true) class  TestModule  { } if  (test)  {    graph  =  graph.add(new  TestModule()); }    @Provide  @Singleton    public  Twitter  provideTwitter()  {        return  new  FakeTwitter();    }

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

Dagger square.github.io/dagger

Slide 42

Slide 42 text

square.github.io