Writing reliable tests is not easy for many reasons, especially when asynchronous code is involved. Some libraries can be used to create a testable architecture (for example Dagger and RxJava) and to simplify testing (Mockito, AssertJ and DaggerMock). In this talk you'll learn how to write JVM and Espresso tests with particular attention on how to replace real objects with mocks and how to test asynchronous RxJava code. In this talk, you will also explore:
how to take advantage of Mockito and other libraries to write good JVM and Espresso tests in both Java and Kotlin
how to use DaggerMock (an open source library available on github to avoid boilerplate code in tests
how to test asynchronous RxJava code using a JVM test
18. 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
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. class MyTest {
@Rule val mockitoRule = MockitoJUnit.rule()
@Mock internal var collaborator1: Collaborator1? = null
@Mock internal var collaborator2: Collaborator2? = null
@InjectMocks internal var objectUnderTest: ObjectUnderTest? = null
@Test fun myTestMethod() {
//Arrange
`when`(collaborator1!!.provideValue()).thenReturn(2)
//Act
objectUnderTest!!.execute()
//Assert
verify(collaborator2).printValue(10)
assertThat(objectUnderTest!!.value).isEqualTo(10)
}_
}__
22. class MyTest {
val collaborator1: Collaborator1 = mock()
val collaborator2: Collaborator2 = mock()
val objectUnderTest = ObjectUnderTest(collaborator1, collaborator2)
@Test fun myTestMethod() {
//Arrange
whenever(collaborator1.provideValue()).thenReturn(2)
//Act
objectUnderTest.execute()
//Assert
verify(collaborator2).printValue(10)
assertThat(objectUnderTest.value).isEqualTo(10)
}_
}__
23. Methods and classes are final
Define classes and methods as open
Always define interfaces
All open compiler plugin
kotlinlang.org/docs/reference/compiler-plugins.html
MockMaker
hadihariri.com/2016/10/04/Mocking-Kotlin-With-Mockito
DexOpener for instrumentation tests
github.com/tmurakami/dexopener
47. class MockPresenterTest {
@get:Rule val rule = activityRule<UserListActivity>()
@get:Rule
val daggerMockRule = DaggerMock.rule<ApplicationComponent>(
UserInteractorModule()) {
set { appFromInstrumentation.component = it }
}_
val presenter: UserListPresenter = mock()
@Test fun testOnCreate() {
rule.launchActivity(null)
R.id.text hasText ""
verify(presenter).reloadUserList()
}
}
Activity
Presenter
Interactor
Retrofit
Service
48. Testing RxJava code
1.void method that uses
RxJava schedulers
2.method that returns a
synchronous RxJava object
3.method that returns an
asynchronous RxJava object
78. Testing RxJava code
1.void method that uses
RxJava schedulers
2.method that returns a
synchronous RxJava object
3.method that returns an
asynchronous RxJava object
trampoline
scheduler
blockingGet
TestScheduler
& TestObserver
79. Wrapping up
1.Using DaggerMock testing boilerplate code can be
reduced
2.RxJava asynchronous code can be tested using
TestObserver and TestScheduler
3.Test code can be simplified using Kotlin extension
functions