O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Testable Android Apps DroidCon Italy 2015

3.127 visualizações

Publicada em

What’s the best testing framework on Android? Espresso or Robotium? Robolectric or a plain JUnit test?
The reason why many developers don’t write tests is not due to the testing libraries but because of the low testability of the Android code.
In this talk we’ll see, thanks to a practical example, how to use Dependency Injection (using Dagger) and the Model View Presenter pattern to write a testable Android application.

Publicada em: Tecnologia
  • D0WNL0AD FULL ▶ ▶ ▶ ▶ http://1url.pw/aqJtg ◀ ◀ ◀ ◀
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui
  • I was always one of those students who were top of the class for maths during my KS3 years. However, we didn't have maths lessons for around 6 months in year 10, so I fell behind rapidly, and I was getting below average for my GCSE mocks. This package has really boosted my knowledge in a matter of only two weeks! I am vastly improving in maths and I am confident, given that I follow Jeevan's principles, I will achieve an A* in GCSE maths... In the end I achieved an 'A' grade in GCSE maths (summer 2014). I was a little disappointed in myself. However, considering the circumstances, I think I did pretty well. I am now taking A-Level maths at a grammar school and wanted to thank you for helping me along the way. You have inspired me to do well in this subject and I'm sure my 'A' grade will definitely help me to study Veterinary Medicine at a top University. Once again, thank you so much! ♥♥♥ http://t.cn/AirraVnG
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (2019 Update) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://soo.gd/irt2 } ......................................................................................................................... Download Full EPUB Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download Full doc Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download PDF EBOOK here { https://soo.gd/irt2 } ......................................................................................................................... Download EPUB Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download doc Ebook here { https://soo.gd/irt2 } ......................................................................................................................... ......................................................................................................................... ................................................................................................................................... eBook is an electronic version of a traditional print book THIS can be read by using a personal computer or by using an eBook reader. (An eBook reader can be a software application for use on a computer such as Microsoft's free Reader application, or a book-sized computer THIS is used solely as a reading device such as Nuvomedia's Rocket eBook.) Users can purchase an eBook on diskette or CD, but the most popular method of getting an eBook is to purchase a downloadable file of the eBook (or other reading material) from a Web site (such as Barnes and Noble) to be read from the user's computer or reading device. Generally, an eBook can be downloaded in five minutes or less ......................................................................................................................... .............. Browse by Genre Available eBooks .............................................................................................................................. Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, ......................................................................................................................... ......................................................................................................................... .....BEST SELLER FOR EBOOK RECOMMEND............................................................. ......................................................................................................................... Blowout: Corrupted Democracy, Rogue State Russia, and the Richest, Most Destructive Industry on Earth,-- The Ride of a Lifetime: Lessons Learned from 15 Years as CEO of the Walt Disney Company,-- Call Sign Chaos: Learning to Lead,-- StrengthsFinder 2.0,-- Stillness Is the Key,-- She Said: Breaking the Sexual Harassment Story THIS Helped Ignite a Movement,-- Atomic Habits: An Easy & Proven Way to Build Good Habits & Break Bad Ones,-- Everything Is Figureoutable,-- What It Takes: Lessons in the Pursuit of Excellence,-- Rich Dad Poor Dad: What the Rich Teach Their Kids About Money THIS the Poor and Middle Class Do Not!,-- The Total Money Makeover: Classic Edition: A Proven Plan for Financial Fitness,-- Shut Up and Listen!: Hard Business Truths THIS Will Help You Succeed, ......................................................................................................................... .........................................................................................................................
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui

Testable Android Apps DroidCon Italy 2015

  1. 1. Testable Android Apps Fabio Collini
  2. 2. DroidCon Italy – Torino – April 2015 – @fabioCollini 2 Fabio Collini @fabioCollini linkedin.com/in/fabiocollini Folder Organizer cosenonjaviste.it nana bianca Freapp instal.com Rain tomorrow?
  3. 3. DroidCon Italy – Torino – April 2015 – @fabioCollini 3 Quick survey Do you write automated tests?
  4. 4. DroidCon Italy – Torino – April 2015 – @fabioCollini 4 Return of Investment - ROI Net profit Investment
  5. 5. DroidCon Italy – Torino – April 2015 – @fabioCollini 5 Agenda 1. Legacy code 2. Dependency Injection 3. Mockito 4. Dagger 5. Dagger & Android 6. Model View Presenter
  6. 6. DroidCon Italy – Torino – April 2015 – @fabioCollini 6 TestableAndroidAppsDroidCon15 https://github.com/fabioCollini/ TestableAndroidAppsDroidCon15
  7. 7. DroidCon Italy - Torino - April 2015 - @fabioCollini 1Legacy code
  8. 8. DroidCon Italy – Torino – April 2015 – @fabioCollini 8 Legacy code Edit and pray Vs Cover and modify Legacy code is code without unit tests
  9. 9. DroidCon Italy – Torino – April 2015 – @fabioCollini 9 Instrumentation tests run on a device (real or emulated) high code coverage Vs JVM tests fast low code coverage
  10. 10. DroidCon Italy – Torino – April 2015 – @fabioCollini 10 Espresso public class PostListActivityTest { //see https://gist.github.com/JakeWharton/1c2f2cadab2ddd97f9fb
 @Rule
 public ActivityRule<PostListActivity> rule = new ActivityRule<>(PostListActivity.class);
 
 } @Test public void showListActivity() {
 onView(withText("???")) .check(matches(isDisplayed()));
 }
 @Test public void showErrorLayoutOnServerError() {
 //???
 onView(withId(R.id.error_layout)) .check(matches(isDisplayed())); }
  11. 11. DroidCon Italy – Torino – April 2015 – @fabioCollini 11 Legacy code dilemma When we change code, we should have tests in place. To put tests in place, we often have to change code. Michael Feathers
  12. 12. DroidCon Italy – Torino – April 2015 – @fabioCollini 12 TestablePostListActivity public class TestablePostListActivity extends PostListActivity {
 
 public static Observable<List<Post>> result;
 
 @Override protected Observable<List<Post>> createListObservable() {
 return result;
 }
 }
  13. 13. DroidCon Italy – Torino – April 2015 – @fabioCollini 13 PostListActivityTest public class PostListActivityTest { 
 @Rule public ActivityRule<TestablePostListActivity> rule = new ActivityRule<>( TestablePostListActivity.class, false );
 
 @Test public void showListActivity() {
 TestablePostListActivity.result = Observable.just(
 createPost(1), createPost(2), createPost(3)
 ).toList();
 
 rule.launchActivity();
 
 onView(withText("title 1”)) .check(matches(isDisplayed()));
 }
  14. 14. DroidCon Italy – Torino – April 2015 – @fabioCollini 14 PostListActivityTest @Test public void checkErrorLayoutDisplayed() {
 TestablePostListActivity.result = Observable.error(new IOException());
 
 rule.launchActivity();
 
 onView(withId(R.id.error_layout)) .check(matches(isDisplayed()));
 }
  15. 15. DroidCon Italy – Torino – April 2015 – @fabioCollini 15 Legacy code Not the perfect solution First step to increase coverage Then modify and refactor
  16. 16. DroidCon Italy - Torino - April 2015 - @fabioCollini 2Dependency Injection
  17. 17. DroidCon Italy – Torino – April 2015 – @fabioCollini 17 PostBatch public void execute() {
 PostResponse postResponse = createService().listPosts();
 EmailSender emailSender = new EmailSender();
 
 List<Post> posts = postResponse.getPosts();
 for (Post post : posts) {
 emailSender.sendEmail(post);
 }
 }
 
 private static WordPressService createService() {
 //...
 }
  18. 18. DroidCon Italy – Torino – April 2015 – @fabioCollini 18 PostBatch WordPressService EmailSender Class under test Collaborator Collaborator
  19. 19. DroidCon Italy – Torino – April 2015 – @fabioCollini 19 PostBatchTest public class PostBatchTest {
 
 private PostBatch postBatch = new PostBatch();
 
 @Test
 public void testExecute() {
 postBatch.execute();
 //???
 }
 }
  20. 20. DroidCon Italy – Torino – April 2015 – @fabioCollini 20 Inversion Of Control private WordPressService wordPressService;
 
 private EmailSender emailSender;
 
 public PostBatch(WordPressService wordPressService, EmailSender emailSender) {
 this.wordPressService = wordPressService;
 this.emailSender = emailSender;
 }
 
 public void execute() {
 PostResponse postResponse = wordPressService.listPosts();
 List<Post> posts = postResponse.getPosts();
 for (Post post : posts) {
 emailSender.sendEmail(post);
 }
 }
  21. 21. DroidCon Italy – Torino – April 2015 – @fabioCollini 21 Dependency Injection public class Main {
 
 public static void main(String[] args) {
 new PostBatch( createService(), new EmailSender() ).execute();
 }
 
 private static WordPressService createService() {
 //...
 }
 }
  22. 22. DroidCon Italy – Torino – April 2015 – @fabioCollini 22 WordPressServiceStub public class WordPressServiceStub implements WordPressService {
 
 private PostResponse postResponse;
 
 public WordPressServiceStub(PostResponse postResponse) {
 this.postResponse = postResponse;
 }
 
 @Override public PostResponse listPosts() {
 return postResponse;
 }
 }
  23. 23. DroidCon Italy – Torino – April 2015 – @fabioCollini 23 EmailSenderSpy public class EmailSenderSpy extends EmailSender {
 
 private int emailCount;
 
 @Override public void sendEmail(Post p) {
 emailCount++;
 }
 
 public int getEmailCount() {
 return emailCount;
 }
 }
  24. 24. DroidCon Italy – Torino – April 2015 – @fabioCollini 24 PostBatch WordPressService EmailSender Stub Spy
  25. 25. DroidCon Italy – Torino – April 2015 – @fabioCollini 25 Test doubles private PostBatch postBatch;
 
 private EmailSenderSpy emailSenderSpy;
 
 private WordPressServiceStub serviceStub; @Test
 public void testExecute() {
 postBatch.execute();
 assertEquals(3, emailSenderSpy.getEmailCount());
 } @Before public void init() {
 emailSenderSpy = new EmailSenderSpy();
 serviceStub = new WordPressServiceStub( new PostResponse(new Post(), new Post(), new Post()) );
 postBatch = new PostBatch(serviceStub, emailSenderSpy);
 }

  26. 26. DroidCon Italy - Torino - April 2015 - @fabioCollini 3Mockito
  27. 27. DroidCon Italy – Torino – April 2015 – @fabioCollini 27 Mockito private WordPressService service;
 private EmailSender emailSender;
 private PostBatch postBatch;
 @Before public void init() {
 emailSender = Mockito.mock(EmailSender.class);
 service = Mockito.mock(WordPressService.class);
 postBatch = new PostBatch(service, emailSender);
 } @Test public void testExecute() {
 when(service.listPosts()).thenReturn( new PostResponse(new Post(), new Post(), new Post()));
 
 postBatch.execute();
 
 verify(emailSender, times(3)).sendEmail(any(Post.class));
 } ArrangeActAssert
  28. 28. DroidCon Italy – Torino – April 2015 – @fabioCollini 28 @InjectMocks @RunWith(MockitoJUnitRunner.class)
 public class PostBatchTest {
 
 @Mock WordPressService service;
 
 @Mock EmailSender sender;
 
 @InjectMocks PostBatch postBatch;
 
 @Test
 public void testExecute() {
 when(service.listPosts()).thenReturn( new PostResponse(new Post(), new Post(), new Post()));
 
 postBatch.execute();
 
 verify(sender, times(3)).sendEmail(any(Post.class));
 }
 }
  29. 29. DroidCon Italy - Torino - April 2015 - @fabioCollini 4Dagger
  30. 30. DroidCon Italy – Torino – April 2015 – @fabioCollini 30 Dagger A fast dependency injector for Android and Java v1 developed at Square https://github.com/square/dagger v2 developed at Google https://github.com/google/dagger Configuration using annotations and Java classes Based on annotation processing (no reflection)
  31. 31. DroidCon Italy – Torino – April 2015 – @fabioCollini 31 Module @Module
 public class MainModule { 
 @Provides @Singleton EmailSender provideEmailSender() {
 return new EmailSender();
 }
 
 @Provides @Singleton WordPressService provideService() {
 //...
 }
 
 @Provides PostBatch providePostsBatch( WordPressService wordPressService, EmailSender emailSender) {
 return new PostBatch(wordPressService, emailSender);
 }
 }
  32. 32. DroidCon Italy – Torino – April 2015 – @fabioCollini 32 PostBatch WordPressService EmailSender Component Main
  33. 33. DroidCon Italy – Torino – April 2015 – @fabioCollini 33 Component @Singleton
 @Component(modules = MainModule.class)
 public interface MainComponent {
 PostBatch getBatch();
 } public class Main {
 public static void main(String[] args) {
 MainComponent component = DaggerMainComponent.create(); PostBatch batch = component.getBatch();
 batch.execute();
 }
 }
  34. 34. DroidCon Italy – Torino – April 2015 – @fabioCollini 34 Inject annotation public class PostBatch {
 private WordPressService wordPressService;
 private EmailSender emailSender;
 
 @Inject public PostBatch( WordPressService wordPressService, EmailSender emailSender) {
 this.wordPressService = wordPressService;
 this.emailSender = emailSender;
 } } public class PostBatch {
 @Inject WordPressService wordPressService;
 @Inject EmailSender emailSender;
 @Inject public PostBatch() {
 }
 }
  35. 35. DroidCon Italy - Torino - April 2015 - @fabioCollini 5Dagger & Android
  36. 36. DroidCon Italy – Torino – April 2015 – @fabioCollini 36 PostListActivity WordPressService ShareActivity ShareExecutor
  37. 37. DroidCon Italy – Torino – April 2015 – @fabioCollini 37 ShareExecutor public class ShareExecutor {
 private Context context; 
 public ShareExecutor(Context context) {
 this.context = context;
 }
 
 public void startSendActivity(String title, String body) {
 Intent intent = new Intent();
 intent.setAction(Intent.ACTION_SEND);
 intent.putExtra(Intent.EXTRA_TITLE, title);
 intent.putExtra(Intent.EXTRA_TEXT, body);
 intent.setType("text/plain");
 Intent chooserIntent = Intent.createChooser(intent, context.getResources().getText(R.string.share));
 chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(chooserIntent); }
 }
  38. 38. DroidCon Italy – Torino – April 2015 – @fabioCollini 38 ApplicationModule @Module public class ApplicationModule {
 private Application application;
 public ApplicationModule(Application application) {
 this.application = application;
 } 
 @Provides @Singleton WordPressService providesService() {
 //...
 }
 @Provides @Singleton ShareExecutor shareExecutor() {
 return new ShareExecutor(application);
 }
 }
  39. 39. DroidCon Italy – Torino – April 2015 – @fabioCollini 39 ApplicationComponent @Singleton @Component(modules = ApplicationModule.class)
 public interface ApplicationComponent { 
 void inject(PostListActivity activity);
 void inject(ShareActivity activity); }
  40. 40. DroidCon Italy – Torino – April 2015 – @fabioCollini 40 Component PostListActivity Application ShareActivity ShareExecutorWordPressService
  41. 41. DroidCon Italy – Torino – April 2015 – @fabioCollini 41 Application public class CnjApplication extends Application {
 
 private ApplicationComponent component;
 
 @Override public void onCreate() {
 super.onCreate();
 component = DaggerApplicationComponent.builder()
 .applicationModule(new ApplicationModule(this))
 .build();
 }
 
 public ApplicationComponent getComponent() {
 return component;
 }
 
 public void setComponent(ApplicationComponent c) {
 this.component = c;
 }
 }
  42. 42. DroidCon Italy – Torino – April 2015 – @fabioCollini 42 PostListActivity public class PostListActivity extends ActionBarActivity {
 //...
 @Inject WordPressService wordPressService;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 CnjApplication app = (CnjApplication) getApplicationContext(); ApplicationComponent component = app.getComponent();
 component.inject(this);
 
 //...
 }
 //...
 }
  43. 43. DroidCon Italy – Torino – April 2015 – @fabioCollini 43 Component PostListActivity Application ShareExecutorWordPressService TestComponent MockMock Test
  44. 44. DroidCon Italy – Torino – April 2015 – @fabioCollini 44 TestModule @Module
 public class TestModule {
 @Provides @Singleton ShareExecutor provideShareExecutor() {
 return Mockito.mock(ShareExecutor.class);
 }
 @Provides @Singleton WordPressService providesWordPressService() {
 return Mockito.mock(WordPressService.class);
 }
 }
  45. 45. DroidCon Italy – Torino – April 2015 – @fabioCollini 45 TestComponent @Singleton
 @Component(modules = TestModule.class)
 public interface TestComponent extends ApplicationComponent {
 void inject(PostListActivityTest test);
 
 void inject(ShareActivityTest test);
 }
  46. 46. DroidCon Italy – Torino – April 2015 – @fabioCollini 46 PostListActivityTest public class PostListActivityTest {
 
 @Inject WordPressService wordPressService;
 
 @Rule public ActivityRule<PostListActivity> rule = new ActivityRule<>(PostListActivity.class, false);
 @Before public void setUp() {
 TestComponent component = DaggerTestComponent.create();
 CnjApplication application = (CnjApplication) rule.getApplication();
 application.setComponent(component);
 component.inject(this);
 } //...
  47. 47. DroidCon Italy – Torino – April 2015 – @fabioCollini 47 PostListActivityTest @Test public void showListActivity() {
 when(wordPressService.listPosts()).thenReturn( Observable.just(new PostResponse(createPost(1), createPost(2), createPost(3))));
 
 rule.launchActivity();
 
 onView(withText("title 1”)) .check(matches(isDisplayed()));
 }
  48. 48. DroidCon Italy – Torino – April 2015 – @fabioCollini 48 PostListActivityTest 
 @Test public void showErrorLayoutOnServerError() {
 when(wordPressService.listPosts()).thenReturn( Observable.error(new IOException("error!")));
 
 rule.launchActivity();
 
 onView(withId(R.id.error_layout)) .check(matches(isDisplayed()));
 }
  49. 49. DroidCon Italy - Torino - April 2015 - @fabioCollini 6Model View Presenter
  50. 50. DroidCon Italy – Torino – April 2015 – @fabioCollini 50 Model View Presenter View Presenter Model
  51. 51. DroidCon Italy – Torino – April 2015 – @fabioCollini 51 View Presenter RetrofitService onClick update update(model) Model View Presenter RetrofitServiceModel request response
  52. 52. DroidCon Italy – Torino – April 2015 – @fabioCollini 52 View Presenter MockService perform(click()) update update(model) Model request response EspressoTest View Presenter MockServiceModelEspressoTest onView verify when().thenReturn() onClick
  53. 53. DroidCon Italy – Torino – April 2015 – @fabioCollini 53 MockView Presenter MockService onClick update update(model) Model request response JVM Test MockView Presenter MockServiceModelJVM Test verify verify assert when().thenReturn()
  54. 54. DroidCon Italy – Torino – April 2015 – @fabioCollini 54 View Presenter init update(model) ModelEspressoTest View Presenter ModelEspressoTest onView create
  55. 55. DroidCon Italy – Torino – April 2015 – @fabioCollini 55 Android Model View Presenter Activity (or Fragment) is the View All the business logic is in the Presenter Presenter is managed using Dagger Model is the Activity (or Fragment) state Presenter is retained on configuration change
  56. 56. DroidCon Italy – Torino – April 2015 – @fabioCollini 56 PostListPresenter JVM Test @RunWith(MockitoJUnitRunner.class)
 public class PostListPresenterTest {
 
 @Mock WordPressService wordPressService;
 
 @Mock PostListActivity view;
 
 private PostListPresenter postListPresenter;
 
 @Before public void setUp() { SchedulerManager schedulerManager = new SchedulerManager( Schedulers.immediate(), Schedulers.immediate()); 
 postListPresenter = new PostListPresenter( wordPressService, schedulerManager );
 }
 //...
  57. 57. DroidCon Italy – Torino – April 2015 – @fabioCollini 57 PostListPresenter JVM Test @Test
 public void loadingPosts() { when(wordPressService.listPosts()).thenReturn( Observable.just(new PostResponse(new Post(), new Post(), new Post())));
 
 PostListModel model = new PostListModel();
 postListPresenter.setModel(model);
 postListPresenter.resume(view);
 
 assertEquals(3, model.getItems().size());
 }
  58. 58. DroidCon Italy – Torino – April 2015 – @fabioCollini 58 PostListPresenter JVM Test @Test
 public void clickOnItem() {
 PostListModel model = new PostListModel();
 model.setItems(Arrays.asList( createPost(1), createPost(2), createPost(3)));
 postListPresenter.setModel(model);
 postListPresenter.resume(view);
 
 postListPresenter.onItemClick(1);
 
 verify(view).startShareActivity( eq("title 2"), eq("name 2 last name 2nexcerpt 2"));
 }
  59. 59. DroidCon Italy – Torino – April 2015 – @fabioCollini 59 SharePresenter JVM Test @RunWith(MockitoJUnitRunner.class)
 public class SharePresenterTest {
 
 @Mock ShareExecutor shareExecutor;
 
 @Mock ShareActivity view;
 
 @InjectMocks SharePresenter sharePresenter;
 
 @Test public void testValidationOk() { ShareModel model = new ShareModel();
 sharePresenter.init(view, model);
 
 sharePresenter.share("title", "body");
 
 verify(shareExecutor) .startSendActivity(eq("title"), eq("body"));
 }
 }
  60. 60. DroidCon Italy – Torino – April 2015 – @fabioCollini 60 TL;DR Dagger Mockito Espresso UI tests JVM Presenter tests
  61. 61. DroidCon Italy – Torino – April 2015 – @fabioCollini 61 Thanks for your attention! Questions? github.com/fabioCollini/ TestableAndroidAppsDroidCon15 github.com/google/dagger mockito.org cosenonjaviste.it/libri

×