Android Clean Architecture
Testing the remote source implementation
Up next
Previous
About
The Remote layer allows us to abstract the remote source of data that our application uses. To ensure that this layer operates as intended through time, we're going to need tests. In this lesson, we'll be writing the test for our remote source implementation class.
Instructor
Links
Comments
Interesting. Before watching your video I made an attempt at creating the getProjectsCompletes function and came up with the following code:
private fun stubServiceSearchRepositories(observable: Observable){
whenever(service.searchRepositories(any(), any(), any()))
.thenReturn(observable)
}
@Test
fun getProjectsCompletes() {
stubServiceSearchRepositories(Observable.just(ProjectDataFactory.makeProjectsResponse()))
val testObserver = remote.getProjects().test()
testObserver.assertComplete()
}
Notice that I did NOT stub the mapper class. When I ran the test it passed, so the method completed even without the mapper stub. Care to tell me why this is?
Also your sample code link is pointing to the wrong class, but it looks like this repo does not contain this code (unfortunately)
Will update the link! It is on the repo at this point: https://github.com/hitherejoe/GithubTrending/blob/task/remote/Remote/src/test/java/co/joebirch/remote/ProjectsRemoteImplTest.kt - does this work for you?
Joe I'm working my way through this tutorial and I've gotten really confused. I think next time you create a tutorial, especially one this extensive you need to tell people at the end of every video to always look at the source code for any last minute changes. I've gotten all the way to "Testing the Projects Cache Implementation" and I could not get my tests to pass. While trying to troubleshoot my problem, I started to notice a LOT of changes that you've made to the code, mainly changing our getProjects calls from Observables to Flowables. Can you explain why you did this? Anway now I'm going back and changing all the various interfaces to Flowables and a bunch of stuff is breaking. My latest break is the ProjectsRemoteImplTest. The function stubGithubTrendingServiceSearchRepositories is returning an Observable, but the implementation class wants a Flowable.
Hello Joe.
My tests doesn't work. This is the error stacktrace from the "Run" tab of Android Studio:
"/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java" ...
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class br.cericatto.remote.mapper.ProjectsResponseModelMapper
Mockito cannot mock/spy because :
- final class
at br.cericatto.remote.ProjectsRemoteImplTest.(ProjectsRemoteImplTest.kt:113)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class br.cericatto.remote.mapper.ProjectsResponseModelMapper
Mockito cannot mock/spy because :
- final class
at br.cericatto.remote.ProjectsRemoteImplTest.(ProjectsRemoteImplTest.kt:113)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class br.cericatto.remote.mapper.ProjectsResponseModelMapper
Mockito cannot mock/spy because :
- final class
at br.cericatto.remote.ProjectsRemoteImplTest.(ProjectsRemoteImplTest.kt:113)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class br.cericatto.remote.mapper.ProjectsResponseModelMapper
Mockito cannot mock/spy because :
- final class
at br.cericatto.remote.ProjectsRemoteImplTest.(ProjectsRemoteImplTest.kt:113)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Process finished with exit code 255
for anyone having difficulty with the test especially return data.
The code snippet below works.
@Test
fun getProjectsReturnsData(){
val response = ProjectDataFactory.makeProjectsResponse()
stubGithubTrendingServiceSearchRepositories(Observable.just(response))
val entities = mutableListOf()
response.items.forEach {
val entity = ProjectDataFactory.makeProjectEntity()
entities.addAll(listOf(entity))
stubProjectResponseModelMapperMapFromModel(it,entity)
}
val testObserver = remote.getProjects().test()
testObserver.assertValue(entities)
}
Lessons in Android Clean Architecture















































































