SlideShare uma empresa Scribd logo
1 de 79
Baixar para ler offline
Testing Android apps based on
Dagger and RxJava
Fabio Collini
droidcon Italy April 2017
2
Ego slide
@fabioCollini
linkedin.com/in/fabiocollini
github.com/fabioCollini
medium.com/@fabioCollini
codingjam.it
3
Agenda
1. Dagger
2. Testing
3. Mockito
4. Espresso
5. DaggerMock
6. RxJava
4
github.com/fabioCollini/TestingDaggerRxJava
5
Activity
Presenter
Interactor
Retrofit
Service
Rx
Rx
@Singleton
@Provides
@Singleton
@Provides
@Provides@Inject
public interface StackOverflowService {



@GET("/users") 

Single<List<User>> getTopUsers();



@GET("/users/{userId}/badges") 

Single<List<Badge>> getBadges(@Path("userId") int userId);

}
Activity
Presenter
Interactor
Retrofit
Service
Rx
Rx
SingletonSingleton
public class UserInteractor {

private StackOverflowService service;



public UserInteractor(StackOverflowService service) {

this.service = service;

}



public Single<List<UserStats>> loadUsers() {

//...

}

}
Activity
Presenter
Interactor
Retrofit
Service
Rx
Rx
SingletonSingleton
public class UserListPresenter {b



private UserInteractor userInteractor;



private UserListActivity activity;



public UserListPresenter(UserInteractor userInteractor,
UserListActivity activity) {

this.userInteractor = userInteractor;

this.activity = activity;

}onCreate



public void reloadUserList() {

userInteractor
.loadUsers()

//...

.subscribe(

activity::updateText,

activity::showError

);

}showError

}end
Activity
Presenter
Interactor
Retrofit
Service
Rx
Rx
SingletonSingleton
public class UserListActivity extends AppCompatActivity {b



@Inject UserListPresenter presenter;



@Override

protected void onCreate(Bundle savedInstanceState) {
//...
((MyApp) getApplicationContext()).getComponent()

.userListComponent(new UserListModule(this)).inject(this);

presenter.reloadUserList();

}onCreate



public void updateText(String s) {
//...
}updateText



public void showError(Throwable t) {
//...
}showError

}end
Activity
Presenter
Interactor
Retrofit
Service
Rx
Rx
SingletonSingleton
10
@Singleton

@Component(modules = {UserInteractorModule.class, StackOverflowServiceModule.class})

public interface ApplicationComponent {

UserListComponent userListComponent(UserListModule module);

}
@Module

public class UserInteractorModule {

@Provides @Singleton
public UserInteractor provideInteractor() {

//...

}

} @Module

public class StackOverflowServiceModule {

@Provides @Singleton
public StackOverflowService provideService() {

//...

}

}
@Subcomponent(modules = UserListModule.class)

public interface UserListComponent {

void inject(UserListActivity activity);

}
@Module

public class UserListModule {

@Provides
public UserListPresenter providePresenter() {

//...

}

}
Activity
Presenter
Interactor
Retrofit
Service
UnitUnitUnit
Integration
UI
UI
UI
E2E
Espresso JVM
12
Return Of Investment
Net profit
Investment
13
14
15
16
Unit
E2E
Integration
Manual
tests
Testing pyramid
17
Integrated tests are a scam
a self-replicating virus that threatens to infect your
code base, your project, and your team with endless
pain and suffering.
J. B. Rainsberger
18
Mockito tips
public class MyTest {



Collaborator1 collaborator1;



Collaborator2 collaborator2;



ObjectUnderTest objectUnderTest;



@Before

public void setUp() {

collaborator1 = Mockito.mock(Collaborator1.class);

collaborator2 = Mockito.mock(Collaborator2.class);

objectUnderTest = new ObjectUnderTest(
collaborator1, collaborator2);

}setUp



@Test

public void myTestMethod() {

//Arrange

when(collaborator1.provideValue()).thenReturn(2);

//Act

objectUnderTest.execute();

//Assert

verify(collaborator2).printValue(10);

assertThat(objectUnderTest.getValue()).isEqualTo(10);

}_

}__
public class MyTest {



@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();



@Mock Collaborator1 collaborator1;



@Mock Collaborator2 collaborator2;



@InjectMocks ObjectUnderTest objectUnderTest;



@Test

public void myTestMethod() {

//Arrange

when(collaborator1.provideValue()).thenReturn(2);

//Act

objectUnderTest.execute();

//Assert

verify(collaborator2).printValue(10);

assertThat(objectUnderTest.getValue()).isEqualTo(10);

}_

}__
package org.mockito.configuration;

//...
public class MockitoConfiguration extends DefaultMockitoConfiguration {

public Answer<Object> getDefaultAnswer() {

return new ReturnsEmptyValues() {

@Override

public Object answer(InvocationOnMock inv) {

Class<?> type = inv.getMethod().getReturnType();

if (type.isAssignableFrom(Observable.class)) {

return Observable.error(createException(inv));

} else if (type.isAssignableFrom(Single.class)) {

return Single.error(createException(inv));

} else {

return super.answer(inv);

}

}

};

}



private RuntimeException createException(

InvocationOnMock invocation) {

String s = invocation.toString();

return new RuntimeException(

"No mock defined for invocation " + s);

}

}
Espresso
Activity
Presenter
Interactor
Retrofit
Service
public class UserListPresenter {



private UserInteractor userInteractor;



private UserListActivity activity;



public UserListPresenter(UserInteractor userInteractor,
UserListActivity activity) {

this.userInteractor = userInteractor;

this.activity = activity;

}



public void reloadUserList() {

userInteractor

.loadUsers()

.flattenAsObservable(l -> l)

.map(UserStats::toString)

.reduce((s1, s2) -> s1 + "nn" + s2)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(

activity::updateText,

activity::showError

);

}

}
Activity
Presenter
Interactor
Retrofit
Service
@Singleton

@Component(modules = {

TestUserInteractorModule.class,

StackOverflowServiceModule.class

})

public interface TestApplicationComponent

extends ApplicationComponent {

void inject(UserListActivityTest userListActivityTest);

}
Activity
Presenter
Interactor
Retrofit
Service
@Module

public class TestUserInteractorModule {

@Provides @Singleton

public UserInteractor provideUserInteractor() {

return Mockito.mock(UserInteractor.class);

}

}
public class UserListActivityTest {

@Rule public ActivityTestRule<UserListActivity> rule =

new ActivityTestRule<>(UserListActivity.class, false, false);



@Inject UserInteractor userInteractor;



@Before public void setUp() {

TestApplicationComponent component =

DaggerTestApplicationComponent.create();

getAppFromInstrumentation().setComponent(component);

component.inject(this);

}A



@Test public void shouldDisplayUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



rule.launchActivity(null);



onView(withId(R.id.text)).check(matches(withText(

"50 user1 - badge1nn30 user2 - badge2, badge3")));

}B

}C
Activity
Presenter
Interactor
Retrofit
Service
public class UserListActivityTest {

@Rule public ActivityTestRule<UserListActivity> rule =

new ActivityTestRule<>(UserListActivity.class, false, false);



@Inject UserInteractor userInteractor;



@Before public void setUp() {

TestApplicationComponent component =

DaggerTestApplicationComponent.create();

getAppFromInstrumentation().setComponent(component);

component.inject(this);

}A



@Test public void shouldDisplayUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



rule.launchActivity(null);



onView(withId(R.id.text)).check(matches(withText(

"50 user1 - badge1nn30 user2 - badge2, badge3")));

}B

}C
Activity
Presenter
Interactor
Retrofit
Service
ArrangeActAssert
Activity
Presenter
Interactor
Retrofit
Service
public class UserListPresenter {



private UserInteractor userInteractor;



private UserListActivity activity;



public UserListPresenter(UserInteractor userInteractor,
UserListActivity activity) {

this.userInteractor = userInteractor;

this.activity = activity;

}___



public void reloadUserList() {

userInteractor

.loadUsers()

.flattenAsObservable(l -> l)

.map(UserStats::toString)

.reduce((s1, s2) -> s1 + "nn" + s2)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(

activity::updateText,

activity::showError

);

}__

}_
Scheduler asyncTaskScheduler =

Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR);
public class AsyncTaskSchedulerRule implements TestRule {



private final Scheduler asyncTaskScheduler =

Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR);



@Override

public Statement apply(final Statement base, Description d) {

return new Statement() {

@Override

public void evaluate() throws Throwable {

RxJavaPlugins.setIoSchedulerHandler(

scheduler -> asyncTaskScheduler);

RxJavaPlugins.setComputationSchedulerHandler(

scheduler -> asyncTaskScheduler);

RxJavaPlugins.setNewThreadSchedulerHandler(

scheduler -> asyncTaskScheduler);



try {

base.evaluate();

} finally {

RxJavaPlugins.reset();

}

}

};

}

}
public class UserListActivityTest {

@Rule public ActivityTestRule<UserListActivity> rule =

new ActivityTestRule<>(UserListActivity.class, false, false);

@Rule public AsyncTaskSchedulerRule asyncTaskSchedulerRule =
new AsyncTaskSchedulerRule();


@Inject UserInteractor userInteractor;



@Before public void setUp() {

TestApplicationComponent component =

DaggerTestApplicationComponent.create();

getAppFromInstrumentation().setComponent(component);

component.inject(this);

}A



@Test public void shouldDisplayUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



rule.launchActivity(null);



onView(withId(R.id.text)).check(matches(withText(

"50 user1 - badge1nn30 user2 - badge2, badge3")));

}B

}C
Activity
Presenter
Interactor
Retrofit
Service
ArrangeActAssert
public class UserListActivityTest {

@Rule public ActivityTestRule<UserListActivity> rule =

new ActivityTestRule<>(UserListActivity.class, false, false);

@Rule public AsyncTaskSchedulerRule asyncTaskSchedulerRule =
new AsyncTaskSchedulerRule();


@Inject UserInteractor userInteractor;



@Before public void setUp() {

TestApplicationComponent component =

DaggerTestApplicationComponent.create();

getAppFromInstrumentation().setComponent(component);

component.inject(this);

}A



@Test public void shouldDisplayUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



rule.launchActivity(null);



onView(withId(R.id.text)).check(matches(withText(

"50 user1 - badge1nn30 user2 - badge2, badge3")));

}B

}C
Activity
Presenter
Interactor
Retrofit
Service
ArrangeActAssert
@Singleton

@Component(modules = {

TestUserInteractorModule.class,

StackOverflowServiceModule.class

})

public interface TestApplicationComponent

extends ApplicationComponent {

void inject(UserListActivityTest userListActivityTest);

}_
Activity
Presenter
Interactor
Retrofit
Service
@Module

public class TestUserInteractorModule {

@Provides @Singleton

public UserInteractor provideUserInteractor() {

return Mockito.mock(UserInteractor.class);

}

}
//...

@Inject UserInteractor userInteractor;



@Before public void setUp() {

TestApplicationComponent component =

DaggerTestApplicationComponent.create();

getAppFromInstrumentation().setComponent(component);

component.inject(this);

}__
//...
Activity
Presenter
Interactor
Retrofit
Service
//...
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();



@Mock UserInteractor userInteractor;



@Before public void setUp() {

ApplicationComponent component =

DaggerApplicationComponent.builder()

.userInteractorModule(new UserInteractorModule() {

@Override

public UserInteractor provideUserInteractor(

StackOverflowService service) {

return userInteractor;

}___

})

.build();

getAppFromInstrumentation().setComponent(component);

}__
//...
34
//...
@Rule
public DaggerMockRule<ApplicationComponent> daggerMockRule =

new DaggerMockRule<>(

ApplicationComponent.class,

new UserInteractorModule()

).set(component ->

getAppFromInstrumentation().setComponent(component));



@Mock UserInteractor userInteractor;
//...
Activity
Presenter
Interactor
Retrofit
Service
Activity
Presenter
Interactor
Retrofit
Service
public class UserListActivityTest {

@Rule public ActivityTestRule<UserListActivity> rule =

new ActivityTestRule<>(UserListActivity.class, false, false);



@Rule public AsyncTaskSchedulerRule asyncTaskSchedulerRule =
new AsyncTaskSchedulerRule();


@Rule
public DaggerMockRule<ApplicationComponent> daggerMockRule =

new DaggerMockRule<>(

ApplicationComponent.class,

new UserInteractorModule()

).set(component ->

getAppFromInstrumentation().setComponent(component));



@Mock UserInteractor userInteractor;



@Test public void shouldDisplayUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



rule.launchActivity(null);



onView(withId(R.id.text)).check(matches(withText(

"50 user1 - badge1nn30 user2 - badge2, badge3")));

}

}
static <T> T createSubclass(final T module,
final Map<Class, Object> testFields) {

return (T) Mockito.mock(module.getClass(), new Answer() {

@Override public Object answer(InvocationOnMock invocation)
throws Throwable {

Method method = invocation.getMethod();

Object obj = testFields.get(method.getReturnType());

if (obj != null) {

return obj;

} else {

return method.invoke(module, invocation.getArguments());

}

}

});

}
DaggerMock internals
Activity
Presenter
Interactor
Retrofit
Service
@Rule
public DaggerMockRule<ApplicationComponent> daggerMockRule =

new DaggerMockRule<>(

ApplicationComponent.class,

new UserInteractorModule()

).set(component ->

getAppFromInstrumentation().setComponent(component));
Activity
Presenter
Interactor
Retrofit
Service
public class MyDaggerMockRule

extends DaggerMockRule<ApplicationComponent> {



public MyDaggerMockRule() {

super(

ApplicationComponent.class,

new UserInteractorModule()

);

set(component ->

getAppFromInstrumentation().setComponent(component));


providesMock(UserInteractor.class, userInteractor ->

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList())

);

}__

}_
Espresso
Activity
Presenter
Interactor
Retrofit
Service
41
public class MockPresenterTest {



@Rule public ActivityTestRule<UserListActivity> rule =

new ActivityTestRule<>(UserListActivity.class, false, false);



@Rule public MyDaggerMockRule daggerMockRule =

new MyDaggerMockRule();



@Mock UserListPresenter presenter;



@Test

public void testOnCreate() {

rule.launchActivity(null);



onView(withId(R.id.text)).check(matches(withText("")));



verify(presenter).reloadUserList();

}

}
Activity
Presenter
Interactor
Retrofit
Service
1.void method that uses
RxJava schedulers
2.method that returns a
synchronous RxJava object
3.method that returns an
asynchronous RxJava object
Testing RxJava code
Activity
Presenter
Interactor
Retrofit
Service
JVM
public class UserListPresenter {



private UserInteractor userInteractor;



private UserListActivity activity;



public UserListPresenter(UserInteractor userInteractor,
UserListActivity activity) {

this.userInteractor = userInteractor;

this.activity = activity;

}



public void reloadUserList() {

userInteractor

.loadUsers()

.flattenAsObservable(l -> l)

.map(UserStats::toString)

.reduce((s1, s2) -> s1 + "nn" + s2)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(

activity::updateText,

activity::showError

);

}_

}
Activity
Presenter
Interactor
Retrofit
Service
Activity
Presenter
Interactor
Retrofit
Service
public void reloadUserList() {

userInteractor

.loadUsers()

.flattenAsObservable(l -> l)

.map(UserStats::toString)

.reduce((s1, s2) -> s1 + "nn" + s2)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(

activity::updateText,

activity::showError

);

}_

public class UserListPresenterTest {



@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();



@Mock UserInteractor userInteractor;



@Mock UserListActivity activity;



@InjectMocks UserListPresenter presenter;



@Test

public void shouldLoadUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());

presenter.reloadUserList();

verify(activity).updateText(anyString());

}_

}__
Activity
Presenter
Interactor
Retrofit
Service
47
48
public class TrampolineSchedulerRule implements TestRule {



@Override

public Statement apply(final Statement base, Description d) {

return new Statement() {

@Override

public void evaluate() throws Throwable {

RxJavaPlugins.setIoSchedulerHandler(

scheduler -> Schedulers.trampoline());

RxJavaPlugins.setComputationSchedulerHandler(

scheduler -> Schedulers.trampoline());

RxJavaPlugins.setNewThreadSchedulerHandler(

scheduler -> Schedulers.trampoline());

RxAndroidPlugins.setInitMainThreadSchedulerHandler(

scheduler -> Schedulers.trampoline());



try {

base.evaluate();

} finally {

RxJavaPlugins.reset();

RxAndroidPlugins.reset();

}

}

};

}

}
Activity
Presenter
Interactor
Retrofit
Service
public class UserListPresenterTest {



@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();

@Rule public TrampolineSchedulerRule schedulerRule =

new TrampolineSchedulerRule();



@Mock UserInteractor userInteractor;



@Mock UserListActivity activity;



@InjectMocks UserListPresenter presenter;



@Test

public void shouldLoadUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



presenter.reloadUserList();



verify(activity).updateText(

"50 user1 - badge1nn30 user2 - badge2, badge3");

}__

}_
Activity
Presenter
Interactor
Retrofit
Service
public class UserListPresenterTest {



@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();

@Rule public TrampolineSchedulerRule schedulerRule =

new TrampolineSchedulerRule();



@Mock UserInteractor userInteractor;



@Mock UserListActivity activity;



@InjectMocks UserListPresenter presenter;



@Test

public void shouldLoadUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



presenter.reloadUserList();



verify(activity).updateText(

"50 user1 - badge1nn30 user2 - badge2, badge3");

}__

}_
Activity
Presenter
Interactor
Retrofit
Service
public class UserListPresenterTest {



@Rule public DaggerMockRule<ApplicationComponent> daggerMockRule =

new DaggerMockRule<>(ApplicationComponent.class,
new UserInteractorModule());



@Rule public TrampolineSchedulerRule schedulerRule = 

new TrampolineSchedulerRule();



@Mock UserInteractor userInteractor;



@Mock UserListActivity activity;



@InjectFromComponent(UserListActivity.class) 

UserListPresenter presenter;



@Test

public void shouldLoadUsers() {

when(userInteractor.loadUsers()).thenReturn(

Observable.fromArray(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

).toList());



presenter.reloadUserList();



verify(activity).updateText(

"50 user1 - badge1nn30 user2 - badge2, badge3");

}__

}_
1.void method that uses
RxJava schedulers
2.method that returns a
synchronous RxJava object
3.method that returns an
asynchronous RxJava object
Testing RxJava code
trampoline
scheduler
Activity
Presenter
Interactor
Retrofit
Service
JVM
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractor {

private StackOverflowService service;



public UserInteractor(StackOverflowService service) {

this.service = service;

}



public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.flatMap(user ->

service.getBadges(user.id())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}

}
56
public class UserInteractorTest {

@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();



@Mock StackOverflowService stackOverflowService;



@InjectMocks UserInteractor userInteractor;



@Test

public void shouldLoadUsers() {

when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1")));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3")));

List<UserStats> users = userInteractor.loadUsers().blockingGet();



assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

);
}__
}_
Activity
Presenter
Interactor
Retrofit
Service
1.void method that uses
RxJava schedulers
2.method that returns a
synchronous RxJava object
3.method that returns an
asynchronous RxJava object
Testing RxJava code
trampoline
scheduler
blockingGet
Activity
Presenter
Interactor
Retrofit
Service
public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.flatMap(user ->

service.getBadges(user.id())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}_
Activity
Presenter
Interactor
Retrofit
Service
public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.flatMap(user ->

service.getBadges(user.id())
.subscribeOn(Schedulers.io())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}_
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractorTest {

@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();



@Mock StackOverflowService stackOverflowService;



@InjectMocks UserInteractor userInteractor;



@Test

public void shouldLoadUsers() {

when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1")));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3")));

List<UserStats> users = userInteractor.loadUsers().blockingGet();



assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

);
}__
}_
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractorTest {

@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();



@Mock StackOverflowService stackOverflowService;



@InjectMocks UserInteractor userInteractor;



@Test

public void shouldLoadUsers() {

when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1")));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3")));

List<UserStats> users = userInteractor.loadUsers().blockingGet();



assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

);
}__
}_
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractorTest {

@Rule public MockitoRule mockitoRule =

MockitoJUnit.rule();

@Rule public TrampolineSchedulerRule schedulerRule =

new TrampolineSchedulerRule();



@Mock StackOverflowService stackOverflowService;



@InjectMocks UserInteractor userInteractor;



@Test

public void shouldLoadUsers() {

when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1")));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3")));

List<UserStats> users = userInteractor.loadUsers().blockingGet();



assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

);
}__
}_
Activity
Presenter
Interactor
Retrofit
Service
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



userInteractor.loadUsers()

.test()

.assertNoErrors()

.assertValue(check(users ->

assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
Activity
Presenter
Interactor
Retrofit
Service
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



userInteractor.loadUsers()

.test()

.assertNoErrors()

.assertValue(check(users ->

assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
Activity
Presenter
Interactor
Retrofit
Service
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



userInteractor.loadUsers()

.test()

.assertNoErrors()

.assertValue(check(users ->

assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
public class TestSchedulerRule implements TestRule {

private final TestScheduler testScheduler = new TestScheduler();



public TestScheduler getTestScheduler() {

return testScheduler;

}



@Override

public Statement apply(final Statement base, Description d) {

return new Statement() {

@Override

public void evaluate() throws Throwable {

RxJavaPlugins.setIoSchedulerHandler(

scheduler -> testScheduler);

RxJavaPlugins.setComputationSchedulerHandler(

scheduler -> testScheduler);

RxJavaPlugins.setNewThreadSchedulerHandler(

scheduler -> testScheduler);

RxAndroidPlugins.setMainThreadSchedulerHandler(

scheduler -> Schedulers.trampoline());



try {

base.evaluate();

} finally {

RxJavaPlugins.reset();

RxAndroidPlugins.reset();

}

}

};

}

}
Activity
Presenter
Interactor
Retrofit
Service
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



TestObserver<List<UserStats>> testObserver =

userInteractor.loadUsers().test();



schedulerRule.getTestScheduler()

.advanceTimeBy(2, TimeUnit.SECONDS);



testObserver

.assertNoErrors()

.assertValue(check(users ->

assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



TestObserver<List<UserStats>> testObserver =

userInteractor.loadUsers().test();



schedulerRule.getTestScheduler()

.advanceTimeBy(2, TimeUnit.SECONDS);



testObserver

.assertNoErrors()

.assertValue(check(users ->

assertThat(users).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
Activity
Presenter
Interactor
Retrofit
Service
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractor {

private StackOverflowService service;



public UserInteractor(StackOverflowService service) {

this.service = service;

}___



public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.flatMap(user ->

service.getBadges(user.id())

.subscribeOn(Schedulers.io())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}_

}__
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractor {

private StackOverflowService service;



public UserInteractor(StackOverflowService service) {

this.service = service;

}___



public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.flatMap(user ->

service.getBadges(user.id())

.subscribeOn(Schedulers.io())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}_

}__
public class UserInteractor {

private StackOverflowService service;



public UserInteractor(StackOverflowService service) {

this.service = service;

}___



public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.flatMap(user ->

service.getBadges(user.id())

.subscribeOn(Schedulers.io())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}_

}__
Activity
Presenter
Interactor
Retrofit
Service
Activity
Presenter
Interactor
Retrofit
Service
public class UserInteractor {

private StackOverflowService service;



public UserInteractor(StackOverflowService service) {

this.service = service;

}___



public Single<List<UserStats>> loadUsers() {

return service.getTopUsers()

.flattenAsObservable(l -> l)

.take(5)

.concatMapEager(user ->

service.getBadges(user.id())

.subscribeOn(Schedulers.io())

.map(badges -> UserStats.create(user, badges))

.toObservable()

)____

.toList();

}_

}__
Activity
Presenter
Interactor
Retrofit
Service
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



TestObserver<List<UserStats>> testObserver =

userInteractor.loadUsers().test();



schedulerRule.getTestScheduler()

.advanceTimeBy(2, TimeUnit.SECONDS);



testObserver

.assertNoErrors()

.assertValue(check(l ->

assertThat(l).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
when(stackOverflowService.getTopUsers()).thenReturn(

Observable.fromArray(

User.create(1, 50, "user1"),

User.create(2, 30, "user2")

).toList());



when(stackOverflowService.getBadges(1)).thenReturn(

Single.just(Badge.createList("badge1"))

.delay(2, TimeUnit.SECONDS));

when(stackOverflowService.getBadges(2)).thenReturn(

Single.just(Badge.createList("badge2", "badge3"))

.delay(1, TimeUnit.SECONDS));



TestObserver<List<UserStats>> testObserver =

userInteractor.loadUsers().test();



schedulerRule.getTestScheduler()

.advanceTimeBy(2, TimeUnit.SECONDS);



testObserver

.assertNoErrors()

.assertValue(check(l ->

assertThat(l).containsExactly(

UserStats.create(1, 50, "user1", "badge1"),

UserStats.create(2, 30, "user2", "badge2", "badge3")

)_

));
Activity
Presenter
Interactor
Retrofit
Service
1.void method that uses
RxJava schedulers
2.method that returns a
synchronous RxJava object
3.method that returns an
asynchronous RxJava object
Testing RxJava code
trampoline
scheduler
blockingGet
TestScheduler
& TestObserver
77
Wrapping up
1.JVM tests isolate failures and are fast and
reliable
2.Using DaggerMock testing boilerplate code can
be reduced
3.RxJava asynchronous code can be tested using
TestObserver and TestScheduler
78
Links
github.com/fabioCollini/TestingDaggerRxJava
github.com/fabioCollini/DaggerMock
joel-costigliola.github.io/assertj
medium.com/@fabioCollini/testing-asynchronous-rxjava-code-using-
mockito-8ad831a16877
medium.com/@fabioCollini/android-testing-using-dagger-2-mockito-and-a-custom-junit-
rule-c8487ed01b56
testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html
blog.thecodewhisperer.com/permalink/clearing-up-the-integrated-tests-scam
collectiveidea.com/blog/archives/2016/10/13/retrofitting-espresso/
medium.com/@peter.tackage/an-alternative-to-rxandroidplugins-and-rxjavaplugins-
scheduler-injection-9831bbc3dfaf
artemzin.com/blog/jfyi-overriding-module-classes-with-dagger2/
Thanks for your attention!
Questions?

Mais conteúdo relacionado

Mais procurados

Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xTatsuya Maki
 
Dagger 2 - Injeção de Dependência
Dagger 2 - Injeção de DependênciaDagger 2 - Injeção de Dependência
Dagger 2 - Injeção de DependênciaEdson Menegatti
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutinesFabio Collini
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confFabio Collini
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stackTomáš Kypta
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmFabio Collini
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized projectFabio Collini
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limitsDroidcon Berlin
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for AndroidTomáš Kypta
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsBurt Beckwith
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsGR8Conf
 
Why Kotlin - Apalon Kotlin Sprint Part 1
Why Kotlin - Apalon Kotlin Sprint Part 1Why Kotlin - Apalon Kotlin Sprint Part 1
Why Kotlin - Apalon Kotlin Sprint Part 1Kirill Rozov
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolboxShem Magnezi
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for AndroidTomáš Kypta
 
My way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon SpainMy way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon SpainChristian Panadero
 
Testing Java Code Effectively
Testing Java Code EffectivelyTesting Java Code Effectively
Testing Java Code EffectivelyAndres Almiray
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalyFabio Collini
 

Mais procurados (20)

Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.x
 
droidparts
droidpartsdroidparts
droidparts
 
Dagger 2 - Injeção de Dependência
Dagger 2 - Injeção de DependênciaDagger 2 - Injeção de Dependência
Dagger 2 - Injeção de Dependência
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community conf
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere Stockholm
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Rx java in action
Rx java in actionRx java in action
Rx java in action
 
Android programming -_pushing_the_limits
Android programming -_pushing_the_limitsAndroid programming -_pushing_the_limits
Android programming -_pushing_the_limits
 
Java Quiz - Meetup
Java Quiz - MeetupJava Quiz - Meetup
Java Quiz - Meetup
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 
Why Kotlin - Apalon Kotlin Sprint Part 1
Why Kotlin - Apalon Kotlin Sprint Part 1Why Kotlin - Apalon Kotlin Sprint Part 1
Why Kotlin - Apalon Kotlin Sprint Part 1
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
My way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon SpainMy way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon Spain
 
Testing Java Code Effectively
Testing Java Code EffectivelyTesting Java Code Effectively
Testing Java Code Effectively
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
 

Semelhante a Testing Android apps based on Dagger and RxJava

Cloud native programming model comparison
Cloud native programming model comparisonCloud native programming model comparison
Cloud native programming model comparisonEmily Jiang
 
Android Architecture Components
Android Architecture ComponentsAndroid Architecture Components
Android Architecture ComponentsBurhanuddinRashid
 
Android Architecture Components with Kotlin
Android Architecture Components with KotlinAndroid Architecture Components with Kotlin
Android Architecture Components with KotlinAdit Lal
 
Architecture Components
Architecture ComponentsArchitecture Components
Architecture ComponentsSang Eel Kim
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsHassan Abid
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]Nilhcem
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidDaniel Baccin
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT TalkConstantine Mars
 
Architecture Components
Architecture Components Architecture Components
Architecture Components DataArt
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
softshake 2014 - Java EE
softshake 2014 - Java EEsoftshake 2014 - Java EE
softshake 2014 - Java EEAlexis Hassler
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)Giuseppe Filograno
 

Semelhante a Testing Android apps based on Dagger and RxJava (20)

Android best practices
Android best practicesAndroid best practices
Android best practices
 
Cloud native programming model comparison
Cloud native programming model comparisonCloud native programming model comparison
Cloud native programming model comparison
 
Android Architecture Components
Android Architecture ComponentsAndroid Architecture Components
Android Architecture Components
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
Android Architecture Components with Kotlin
Android Architecture Components with KotlinAndroid Architecture Components with Kotlin
Android Architecture Components with Kotlin
 
Architecture Components
Architecture ComponentsArchitecture Components
Architecture Components
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
 
Ngrx meta reducers
Ngrx meta reducersNgrx meta reducers
Ngrx meta reducers
 
Activity
ActivityActivity
Activity
 
Activity
ActivityActivity
Activity
 
Activity
ActivityActivity
Activity
 
Activity
ActivityActivity
Activity
 
Spring boot
Spring boot Spring boot
Spring boot
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
softshake 2014 - Java EE
softshake 2014 - Java EEsoftshake 2014 - Java EE
softshake 2014 - Java EE
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
 

Mais de Fabio Collini

Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectFabio Collini
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaFabio Collini
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureFabio Collini
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFabio Collini
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinFabio Collini
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018Fabio Collini
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFabio Collini
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFabio Collini
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKFabio Collini
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternFabio Collini
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeFabio Collini
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMFabio Collini
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Fabio Collini
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Fabio Collini
 
Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Fabio Collini
 
Android Widget @ whymca 2011
Android Widget @ whymca 2011Android Widget @ whymca 2011
Android Widget @ whymca 2011Fabio Collini
 

Mais de Fabio Collini (16)

Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean Architecture
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUK
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM pattern
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG Firenze
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVM
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
 
Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012
 
Android Widget @ whymca 2011
Android Widget @ whymca 2011Android Widget @ whymca 2011
Android Widget @ whymca 2011
 

Último

DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024APNIC
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024APNIC
 
VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...
VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...
VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...SUHANI PANDEY
 
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.soniya singh
 
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceEnjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceDelhi Call girls
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...Neha Pandey
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Standkumarajju5765
 
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.soniya singh
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersDamian Radcliffe
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...APNIC
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.soniya singh
 
Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...
Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...
Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...SUHANI PANDEY
 
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...singhpriety023
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Real Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirtReal Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirtrahman018755
 
VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...
VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...
VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...SUHANI PANDEY
 
Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...
Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...
Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...SUHANI PANDEY
 

Último (20)

DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024
 
VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...
VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...
VVIP Pune Call Girls Sinhagad WhatSapp Number 8005736733 With Elite Staff And...
 
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
 
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceEnjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
 
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
 
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
 
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
 
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
 
Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...
Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...
Shikrapur - Call Girls in Pune Neha 8005736733 | 100% Gennuine High Class Ind...
 
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
 
Real Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirtReal Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirt
 
VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...
VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...
VIP Model Call Girls NIBM ( Pune ) Call ON 8005736733 Starting From 5K to 25K...
 
Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...
Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...
Ganeshkhind ! Call Girls Pune - 450+ Call Girl Cash Payment 8005736733 Neha T...
 

Testing Android apps based on Dagger and RxJava

  • 1. Testing Android apps based on Dagger and RxJava Fabio Collini droidcon Italy April 2017
  • 3. 3 Agenda 1. Dagger 2. Testing 3. Mockito 4. Espresso 5. DaggerMock 6. RxJava
  • 6. public interface StackOverflowService {
 
 @GET("/users") 
 Single<List<User>> getTopUsers();
 
 @GET("/users/{userId}/badges") 
 Single<List<Badge>> getBadges(@Path("userId") int userId);
 } Activity Presenter Interactor Retrofit Service Rx Rx SingletonSingleton
  • 7. public class UserInteractor {
 private StackOverflowService service;
 
 public UserInteractor(StackOverflowService service) {
 this.service = service;
 }
 
 public Single<List<UserStats>> loadUsers() {
 //...
 }
 } Activity Presenter Interactor Retrofit Service Rx Rx SingletonSingleton
  • 8. public class UserListPresenter {b
 
 private UserInteractor userInteractor;
 
 private UserListActivity activity;
 
 public UserListPresenter(UserInteractor userInteractor, UserListActivity activity) {
 this.userInteractor = userInteractor;
 this.activity = activity;
 }onCreate
 
 public void reloadUserList() {
 userInteractor .loadUsers()
 //...
 .subscribe(
 activity::updateText,
 activity::showError
 );
 }showError
 }end Activity Presenter Interactor Retrofit Service Rx Rx SingletonSingleton
  • 9. public class UserListActivity extends AppCompatActivity {b
 
 @Inject UserListPresenter presenter;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) { //... ((MyApp) getApplicationContext()).getComponent()
 .userListComponent(new UserListModule(this)).inject(this);
 presenter.reloadUserList();
 }onCreate
 
 public void updateText(String s) { //... }updateText
 
 public void showError(Throwable t) { //... }showError
 }end Activity Presenter Interactor Retrofit Service Rx Rx SingletonSingleton
  • 10. 10 @Singleton
 @Component(modules = {UserInteractorModule.class, StackOverflowServiceModule.class})
 public interface ApplicationComponent {
 UserListComponent userListComponent(UserListModule module);
 } @Module
 public class UserInteractorModule {
 @Provides @Singleton public UserInteractor provideInteractor() {
 //...
 }
 } @Module
 public class StackOverflowServiceModule {
 @Provides @Singleton public StackOverflowService provideService() {
 //...
 }
 } @Subcomponent(modules = UserListModule.class)
 public interface UserListComponent {
 void inject(UserListActivity activity);
 } @Module
 public class UserListModule {
 @Provides public UserListPresenter providePresenter() {
 //...
 }
 }
  • 12. 12 Return Of Investment Net profit Investment
  • 13. 13
  • 14. 14
  • 15. 15
  • 17. 17 Integrated tests are a scam a self-replicating virus that threatens to infect your code base, your project, and your team with endless pain and suffering. J. B. Rainsberger
  • 19. public class MyTest {
 
 Collaborator1 collaborator1;
 
 Collaborator2 collaborator2;
 
 ObjectUnderTest objectUnderTest;
 
 @Before
 public void setUp() {
 collaborator1 = Mockito.mock(Collaborator1.class);
 collaborator2 = Mockito.mock(Collaborator2.class);
 objectUnderTest = new ObjectUnderTest( collaborator1, collaborator2);
 }setUp
 
 @Test
 public void myTestMethod() {
 //Arrange
 when(collaborator1.provideValue()).thenReturn(2);
 //Act
 objectUnderTest.execute();
 //Assert
 verify(collaborator2).printValue(10);
 assertThat(objectUnderTest.getValue()).isEqualTo(10);
 }_
 }__
  • 20. public class MyTest {
 
 @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
 
 @Mock Collaborator1 collaborator1;
 
 @Mock Collaborator2 collaborator2;
 
 @InjectMocks ObjectUnderTest objectUnderTest;
 
 @Test
 public void myTestMethod() {
 //Arrange
 when(collaborator1.provideValue()).thenReturn(2);
 //Act
 objectUnderTest.execute();
 //Assert
 verify(collaborator2).printValue(10);
 assertThat(objectUnderTest.getValue()).isEqualTo(10);
 }_
 }__
  • 21. package org.mockito.configuration;
 //... public class MockitoConfiguration extends DefaultMockitoConfiguration {
 public Answer<Object> getDefaultAnswer() {
 return new ReturnsEmptyValues() {
 @Override
 public Object answer(InvocationOnMock inv) {
 Class<?> type = inv.getMethod().getReturnType();
 if (type.isAssignableFrom(Observable.class)) {
 return Observable.error(createException(inv));
 } else if (type.isAssignableFrom(Single.class)) {
 return Single.error(createException(inv));
 } else {
 return super.answer(inv);
 }
 }
 };
 }
 
 private RuntimeException createException(
 InvocationOnMock invocation) {
 String s = invocation.toString();
 return new RuntimeException(
 "No mock defined for invocation " + s);
 }
 }
  • 23. public class UserListPresenter {
 
 private UserInteractor userInteractor;
 
 private UserListActivity activity;
 
 public UserListPresenter(UserInteractor userInteractor, UserListActivity activity) {
 this.userInteractor = userInteractor;
 this.activity = activity;
 }
 
 public void reloadUserList() {
 userInteractor
 .loadUsers()
 .flattenAsObservable(l -> l)
 .map(UserStats::toString)
 .reduce((s1, s2) -> s1 + "nn" + s2)
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 activity::updateText,
 activity::showError
 );
 }
 } Activity Presenter Interactor Retrofit Service
  • 24. @Singleton
 @Component(modules = {
 TestUserInteractorModule.class,
 StackOverflowServiceModule.class
 })
 public interface TestApplicationComponent
 extends ApplicationComponent {
 void inject(UserListActivityTest userListActivityTest);
 } Activity Presenter Interactor Retrofit Service @Module
 public class TestUserInteractorModule {
 @Provides @Singleton
 public UserInteractor provideUserInteractor() {
 return Mockito.mock(UserInteractor.class);
 }
 }
  • 25. public class UserListActivityTest {
 @Rule public ActivityTestRule<UserListActivity> rule =
 new ActivityTestRule<>(UserListActivity.class, false, false);
 
 @Inject UserInteractor userInteractor;
 
 @Before public void setUp() {
 TestApplicationComponent component =
 DaggerTestApplicationComponent.create();
 getAppFromInstrumentation().setComponent(component);
 component.inject(this);
 }A
 
 @Test public void shouldDisplayUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 rule.launchActivity(null);
 
 onView(withId(R.id.text)).check(matches(withText(
 "50 user1 - badge1nn30 user2 - badge2, badge3")));
 }B
 }C Activity Presenter Interactor Retrofit Service
  • 26. public class UserListActivityTest {
 @Rule public ActivityTestRule<UserListActivity> rule =
 new ActivityTestRule<>(UserListActivity.class, false, false);
 
 @Inject UserInteractor userInteractor;
 
 @Before public void setUp() {
 TestApplicationComponent component =
 DaggerTestApplicationComponent.create();
 getAppFromInstrumentation().setComponent(component);
 component.inject(this);
 }A
 
 @Test public void shouldDisplayUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 rule.launchActivity(null);
 
 onView(withId(R.id.text)).check(matches(withText(
 "50 user1 - badge1nn30 user2 - badge2, badge3")));
 }B
 }C Activity Presenter Interactor Retrofit Service ArrangeActAssert
  • 27. Activity Presenter Interactor Retrofit Service public class UserListPresenter {
 
 private UserInteractor userInteractor;
 
 private UserListActivity activity;
 
 public UserListPresenter(UserInteractor userInteractor, UserListActivity activity) {
 this.userInteractor = userInteractor;
 this.activity = activity;
 }___
 
 public void reloadUserList() {
 userInteractor
 .loadUsers()
 .flattenAsObservable(l -> l)
 .map(UserStats::toString)
 .reduce((s1, s2) -> s1 + "nn" + s2)
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 activity::updateText,
 activity::showError
 );
 }__
 }_
  • 29. public class AsyncTaskSchedulerRule implements TestRule {
 
 private final Scheduler asyncTaskScheduler =
 Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR);
 
 @Override
 public Statement apply(final Statement base, Description d) {
 return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 RxJavaPlugins.setIoSchedulerHandler(
 scheduler -> asyncTaskScheduler);
 RxJavaPlugins.setComputationSchedulerHandler(
 scheduler -> asyncTaskScheduler);
 RxJavaPlugins.setNewThreadSchedulerHandler(
 scheduler -> asyncTaskScheduler);
 
 try {
 base.evaluate();
 } finally {
 RxJavaPlugins.reset();
 }
 }
 };
 }
 }
  • 30. public class UserListActivityTest {
 @Rule public ActivityTestRule<UserListActivity> rule =
 new ActivityTestRule<>(UserListActivity.class, false, false);
 @Rule public AsyncTaskSchedulerRule asyncTaskSchedulerRule = new AsyncTaskSchedulerRule(); 
 @Inject UserInteractor userInteractor;
 
 @Before public void setUp() {
 TestApplicationComponent component =
 DaggerTestApplicationComponent.create();
 getAppFromInstrumentation().setComponent(component);
 component.inject(this);
 }A
 
 @Test public void shouldDisplayUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 rule.launchActivity(null);
 
 onView(withId(R.id.text)).check(matches(withText(
 "50 user1 - badge1nn30 user2 - badge2, badge3")));
 }B
 }C Activity Presenter Interactor Retrofit Service ArrangeActAssert
  • 31. public class UserListActivityTest {
 @Rule public ActivityTestRule<UserListActivity> rule =
 new ActivityTestRule<>(UserListActivity.class, false, false);
 @Rule public AsyncTaskSchedulerRule asyncTaskSchedulerRule = new AsyncTaskSchedulerRule(); 
 @Inject UserInteractor userInteractor;
 
 @Before public void setUp() {
 TestApplicationComponent component =
 DaggerTestApplicationComponent.create();
 getAppFromInstrumentation().setComponent(component);
 component.inject(this);
 }A
 
 @Test public void shouldDisplayUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 rule.launchActivity(null);
 
 onView(withId(R.id.text)).check(matches(withText(
 "50 user1 - badge1nn30 user2 - badge2, badge3")));
 }B
 }C Activity Presenter Interactor Retrofit Service ArrangeActAssert
  • 32. @Singleton
 @Component(modules = {
 TestUserInteractorModule.class,
 StackOverflowServiceModule.class
 })
 public interface TestApplicationComponent
 extends ApplicationComponent {
 void inject(UserListActivityTest userListActivityTest);
 }_ Activity Presenter Interactor Retrofit Service @Module
 public class TestUserInteractorModule {
 @Provides @Singleton
 public UserInteractor provideUserInteractor() {
 return Mockito.mock(UserInteractor.class);
 }
 } //...
 @Inject UserInteractor userInteractor;
 
 @Before public void setUp() {
 TestApplicationComponent component =
 DaggerTestApplicationComponent.create();
 getAppFromInstrumentation().setComponent(component);
 component.inject(this);
 }__ //...
  • 33. Activity Presenter Interactor Retrofit Service //... @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
 
 @Mock UserInteractor userInteractor;
 
 @Before public void setUp() {
 ApplicationComponent component =
 DaggerApplicationComponent.builder()
 .userInteractorModule(new UserInteractorModule() {
 @Override
 public UserInteractor provideUserInteractor(
 StackOverflowService service) {
 return userInteractor;
 }___
 })
 .build();
 getAppFromInstrumentation().setComponent(component);
 }__ //...
  • 34. 34
  • 35. //... @Rule public DaggerMockRule<ApplicationComponent> daggerMockRule =
 new DaggerMockRule<>(
 ApplicationComponent.class,
 new UserInteractorModule()
 ).set(component ->
 getAppFromInstrumentation().setComponent(component));
 
 @Mock UserInteractor userInteractor; //... Activity Presenter Interactor Retrofit Service
  • 36. Activity Presenter Interactor Retrofit Service public class UserListActivityTest {
 @Rule public ActivityTestRule<UserListActivity> rule =
 new ActivityTestRule<>(UserListActivity.class, false, false);
 
 @Rule public AsyncTaskSchedulerRule asyncTaskSchedulerRule = new AsyncTaskSchedulerRule(); 
 @Rule public DaggerMockRule<ApplicationComponent> daggerMockRule =
 new DaggerMockRule<>(
 ApplicationComponent.class,
 new UserInteractorModule()
 ).set(component ->
 getAppFromInstrumentation().setComponent(component));
 
 @Mock UserInteractor userInteractor;
 
 @Test public void shouldDisplayUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 rule.launchActivity(null);
 
 onView(withId(R.id.text)).check(matches(withText(
 "50 user1 - badge1nn30 user2 - badge2, badge3")));
 }
 }
  • 37. static <T> T createSubclass(final T module, final Map<Class, Object> testFields) {
 return (T) Mockito.mock(module.getClass(), new Answer() {
 @Override public Object answer(InvocationOnMock invocation) throws Throwable {
 Method method = invocation.getMethod();
 Object obj = testFields.get(method.getReturnType());
 if (obj != null) {
 return obj;
 } else {
 return method.invoke(module, invocation.getArguments());
 }
 }
 });
 } DaggerMock internals
  • 38. Activity Presenter Interactor Retrofit Service @Rule public DaggerMockRule<ApplicationComponent> daggerMockRule =
 new DaggerMockRule<>(
 ApplicationComponent.class,
 new UserInteractorModule()
 ).set(component ->
 getAppFromInstrumentation().setComponent(component));
  • 39. Activity Presenter Interactor Retrofit Service public class MyDaggerMockRule
 extends DaggerMockRule<ApplicationComponent> {
 
 public MyDaggerMockRule() {
 super(
 ApplicationComponent.class,
 new UserInteractorModule()
 );
 set(component ->
 getAppFromInstrumentation().setComponent(component)); 
 providesMock(UserInteractor.class, userInteractor ->
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList())
 );
 }__
 }_
  • 41. 41 public class MockPresenterTest {
 
 @Rule public ActivityTestRule<UserListActivity> rule =
 new ActivityTestRule<>(UserListActivity.class, false, false);
 
 @Rule public MyDaggerMockRule daggerMockRule =
 new MyDaggerMockRule();
 
 @Mock UserListPresenter presenter;
 
 @Test
 public void testOnCreate() {
 rule.launchActivity(null);
 
 onView(withId(R.id.text)).check(matches(withText("")));
 
 verify(presenter).reloadUserList();
 }
 } Activity Presenter Interactor Retrofit Service
  • 42. 1.void method that uses RxJava schedulers 2.method that returns a synchronous RxJava object 3.method that returns an asynchronous RxJava object Testing RxJava code
  • 44. public class UserListPresenter {
 
 private UserInteractor userInteractor;
 
 private UserListActivity activity;
 
 public UserListPresenter(UserInteractor userInteractor, UserListActivity activity) {
 this.userInteractor = userInteractor;
 this.activity = activity;
 }
 
 public void reloadUserList() {
 userInteractor
 .loadUsers()
 .flattenAsObservable(l -> l)
 .map(UserStats::toString)
 .reduce((s1, s2) -> s1 + "nn" + s2)
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 activity::updateText,
 activity::showError
 );
 }_
 } Activity Presenter Interactor Retrofit Service
  • 45. Activity Presenter Interactor Retrofit Service public void reloadUserList() {
 userInteractor
 .loadUsers()
 .flattenAsObservable(l -> l)
 .map(UserStats::toString)
 .reduce((s1, s2) -> s1 + "nn" + s2)
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 activity::updateText,
 activity::showError
 );
 }_

  • 46. public class UserListPresenterTest {
 
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 
 @Mock UserInteractor userInteractor;
 
 @Mock UserListActivity activity;
 
 @InjectMocks UserListPresenter presenter;
 
 @Test
 public void shouldLoadUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 presenter.reloadUserList();
 verify(activity).updateText(anyString());
 }_
 }__ Activity Presenter Interactor Retrofit Service
  • 47. 47
  • 48. 48
  • 49. public class TrampolineSchedulerRule implements TestRule {
 
 @Override
 public Statement apply(final Statement base, Description d) {
 return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 RxJavaPlugins.setIoSchedulerHandler(
 scheduler -> Schedulers.trampoline());
 RxJavaPlugins.setComputationSchedulerHandler(
 scheduler -> Schedulers.trampoline());
 RxJavaPlugins.setNewThreadSchedulerHandler(
 scheduler -> Schedulers.trampoline());
 RxAndroidPlugins.setInitMainThreadSchedulerHandler(
 scheduler -> Schedulers.trampoline());
 
 try {
 base.evaluate();
 } finally {
 RxJavaPlugins.reset();
 RxAndroidPlugins.reset();
 }
 }
 };
 }
 }
  • 50. Activity Presenter Interactor Retrofit Service public class UserListPresenterTest {
 
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 @Rule public TrampolineSchedulerRule schedulerRule =
 new TrampolineSchedulerRule();
 
 @Mock UserInteractor userInteractor;
 
 @Mock UserListActivity activity;
 
 @InjectMocks UserListPresenter presenter;
 
 @Test
 public void shouldLoadUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 presenter.reloadUserList();
 
 verify(activity).updateText(
 "50 user1 - badge1nn30 user2 - badge2, badge3");
 }__
 }_
  • 51. Activity Presenter Interactor Retrofit Service public class UserListPresenterTest {
 
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 @Rule public TrampolineSchedulerRule schedulerRule =
 new TrampolineSchedulerRule();
 
 @Mock UserInteractor userInteractor;
 
 @Mock UserListActivity activity;
 
 @InjectMocks UserListPresenter presenter;
 
 @Test
 public void shouldLoadUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 presenter.reloadUserList();
 
 verify(activity).updateText(
 "50 user1 - badge1nn30 user2 - badge2, badge3");
 }__
 }_
  • 52. Activity Presenter Interactor Retrofit Service public class UserListPresenterTest {
 
 @Rule public DaggerMockRule<ApplicationComponent> daggerMockRule =
 new DaggerMockRule<>(ApplicationComponent.class, new UserInteractorModule());
 
 @Rule public TrampolineSchedulerRule schedulerRule = 
 new TrampolineSchedulerRule();
 
 @Mock UserInteractor userInteractor;
 
 @Mock UserListActivity activity;
 
 @InjectFromComponent(UserListActivity.class) 
 UserListPresenter presenter;
 
 @Test
 public void shouldLoadUsers() {
 when(userInteractor.loadUsers()).thenReturn(
 Observable.fromArray(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ).toList());
 
 presenter.reloadUserList();
 
 verify(activity).updateText(
 "50 user1 - badge1nn30 user2 - badge2, badge3");
 }__
 }_
  • 53. 1.void method that uses RxJava schedulers 2.method that returns a synchronous RxJava object 3.method that returns an asynchronous RxJava object Testing RxJava code trampoline scheduler
  • 55. Activity Presenter Interactor Retrofit Service public class UserInteractor {
 private StackOverflowService service;
 
 public UserInteractor(StackOverflowService service) {
 this.service = service;
 }
 
 public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .flatMap(user ->
 service.getBadges(user.id())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }
 }
  • 56. 56
  • 57. public class UserInteractorTest {
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 
 @Mock StackOverflowService stackOverflowService;
 
 @InjectMocks UserInteractor userInteractor;
 
 @Test
 public void shouldLoadUsers() {
 when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1")));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3")));
 List<UserStats> users = userInteractor.loadUsers().blockingGet();
 
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ); }__ }_ Activity Presenter Interactor Retrofit Service
  • 58. 1.void method that uses RxJava schedulers 2.method that returns a synchronous RxJava object 3.method that returns an asynchronous RxJava object Testing RxJava code trampoline scheduler blockingGet
  • 59. Activity Presenter Interactor Retrofit Service public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .flatMap(user ->
 service.getBadges(user.id())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }_
  • 60. Activity Presenter Interactor Retrofit Service public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .flatMap(user ->
 service.getBadges(user.id()) .subscribeOn(Schedulers.io())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }_
  • 61. Activity Presenter Interactor Retrofit Service public class UserInteractorTest {
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 
 @Mock StackOverflowService stackOverflowService;
 
 @InjectMocks UserInteractor userInteractor;
 
 @Test
 public void shouldLoadUsers() {
 when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1")));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3")));
 List<UserStats> users = userInteractor.loadUsers().blockingGet();
 
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ); }__ }_
  • 62. Activity Presenter Interactor Retrofit Service public class UserInteractorTest {
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 
 @Mock StackOverflowService stackOverflowService;
 
 @InjectMocks UserInteractor userInteractor;
 
 @Test
 public void shouldLoadUsers() {
 when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1")));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3")));
 List<UserStats> users = userInteractor.loadUsers().blockingGet();
 
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ); }__ }_
  • 63. Activity Presenter Interactor Retrofit Service public class UserInteractorTest {
 @Rule public MockitoRule mockitoRule =
 MockitoJUnit.rule();
 @Rule public TrampolineSchedulerRule schedulerRule =
 new TrampolineSchedulerRule();
 
 @Mock StackOverflowService stackOverflowService;
 
 @InjectMocks UserInteractor userInteractor;
 
 @Test
 public void shouldLoadUsers() {
 when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1")));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3")));
 List<UserStats> users = userInteractor.loadUsers().blockingGet();
 
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 ); }__ }_
  • 64. Activity Presenter Interactor Retrofit Service when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 userInteractor.loadUsers()
 .test()
 .assertNoErrors()
 .assertValue(check(users ->
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 ));
  • 65. Activity Presenter Interactor Retrofit Service when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 userInteractor.loadUsers()
 .test()
 .assertNoErrors()
 .assertValue(check(users ->
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 ));
  • 66. Activity Presenter Interactor Retrofit Service when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 userInteractor.loadUsers()
 .test()
 .assertNoErrors()
 .assertValue(check(users ->
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 ));
  • 67. public class TestSchedulerRule implements TestRule {
 private final TestScheduler testScheduler = new TestScheduler();
 
 public TestScheduler getTestScheduler() {
 return testScheduler;
 }
 
 @Override
 public Statement apply(final Statement base, Description d) {
 return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 RxJavaPlugins.setIoSchedulerHandler(
 scheduler -> testScheduler);
 RxJavaPlugins.setComputationSchedulerHandler(
 scheduler -> testScheduler);
 RxJavaPlugins.setNewThreadSchedulerHandler(
 scheduler -> testScheduler);
 RxAndroidPlugins.setMainThreadSchedulerHandler(
 scheduler -> Schedulers.trampoline());
 
 try {
 base.evaluate();
 } finally {
 RxJavaPlugins.reset();
 RxAndroidPlugins.reset();
 }
 }
 };
 }
 }
  • 68. Activity Presenter Interactor Retrofit Service when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 TestObserver<List<UserStats>> testObserver =
 userInteractor.loadUsers().test();
 
 schedulerRule.getTestScheduler()
 .advanceTimeBy(2, TimeUnit.SECONDS);
 
 testObserver
 .assertNoErrors()
 .assertValue(check(users ->
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 ));
  • 69. when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 TestObserver<List<UserStats>> testObserver =
 userInteractor.loadUsers().test();
 
 schedulerRule.getTestScheduler()
 .advanceTimeBy(2, TimeUnit.SECONDS);
 
 testObserver
 .assertNoErrors()
 .assertValue(check(users ->
 assertThat(users).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 )); Activity Presenter Interactor Retrofit Service
  • 70. Activity Presenter Interactor Retrofit Service public class UserInteractor {
 private StackOverflowService service;
 
 public UserInteractor(StackOverflowService service) {
 this.service = service;
 }___
 
 public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .flatMap(user ->
 service.getBadges(user.id())
 .subscribeOn(Schedulers.io())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }_
 }__
  • 71. Activity Presenter Interactor Retrofit Service public class UserInteractor {
 private StackOverflowService service;
 
 public UserInteractor(StackOverflowService service) {
 this.service = service;
 }___
 
 public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .flatMap(user ->
 service.getBadges(user.id())
 .subscribeOn(Schedulers.io())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }_
 }__
  • 72. public class UserInteractor {
 private StackOverflowService service;
 
 public UserInteractor(StackOverflowService service) {
 this.service = service;
 }___
 
 public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .flatMap(user ->
 service.getBadges(user.id())
 .subscribeOn(Schedulers.io())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }_
 }__ Activity Presenter Interactor Retrofit Service
  • 73. Activity Presenter Interactor Retrofit Service public class UserInteractor {
 private StackOverflowService service;
 
 public UserInteractor(StackOverflowService service) {
 this.service = service;
 }___
 
 public Single<List<UserStats>> loadUsers() {
 return service.getTopUsers()
 .flattenAsObservable(l -> l)
 .take(5)
 .concatMapEager(user ->
 service.getBadges(user.id())
 .subscribeOn(Schedulers.io())
 .map(badges -> UserStats.create(user, badges))
 .toObservable()
 )____
 .toList();
 }_
 }__
  • 74. Activity Presenter Interactor Retrofit Service when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 TestObserver<List<UserStats>> testObserver =
 userInteractor.loadUsers().test();
 
 schedulerRule.getTestScheduler()
 .advanceTimeBy(2, TimeUnit.SECONDS);
 
 testObserver
 .assertNoErrors()
 .assertValue(check(l ->
 assertThat(l).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 ));
  • 75. when(stackOverflowService.getTopUsers()).thenReturn(
 Observable.fromArray(
 User.create(1, 50, "user1"),
 User.create(2, 30, "user2")
 ).toList());
 
 when(stackOverflowService.getBadges(1)).thenReturn(
 Single.just(Badge.createList("badge1"))
 .delay(2, TimeUnit.SECONDS));
 when(stackOverflowService.getBadges(2)).thenReturn(
 Single.just(Badge.createList("badge2", "badge3"))
 .delay(1, TimeUnit.SECONDS));
 
 TestObserver<List<UserStats>> testObserver =
 userInteractor.loadUsers().test();
 
 schedulerRule.getTestScheduler()
 .advanceTimeBy(2, TimeUnit.SECONDS);
 
 testObserver
 .assertNoErrors()
 .assertValue(check(l ->
 assertThat(l).containsExactly(
 UserStats.create(1, 50, "user1", "badge1"),
 UserStats.create(2, 30, "user2", "badge2", "badge3")
 )_
 )); Activity Presenter Interactor Retrofit Service
  • 76. 1.void method that uses RxJava schedulers 2.method that returns a synchronous RxJava object 3.method that returns an asynchronous RxJava object Testing RxJava code trampoline scheduler blockingGet TestScheduler & TestObserver
  • 77. 77 Wrapping up 1.JVM tests isolate failures and are fast and reliable 2.Using DaggerMock testing boilerplate code can be reduced 3.RxJava asynchronous code can be tested using TestObserver and TestScheduler
  • 79. Thanks for your attention! Questions?