Sign in Go Pro

Android Clean Architecture

Testing the remote source implementation

This lesson is for PRO members.

Upgrade today to get access to all the PRO lessons.

Unlock this lesson
Autoplay

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?

That's odd! Did you setup the mapper class as a mock within your test class? Usually this occurs when that hasn't been done, as then the mapper will just operate as a normal class and actually perform the mapping :)

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.

Hey Steve, really sorry that you have seen these inconsistencies here. The course ended up being quite big and it looks like some things slipped through the net, I'm working on updating these shortly so that they are all a reflection of the videos

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

Hey Rodrigo,

could you try making ProjectsResponseModelMapper an open class and see if this helps? :)

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)
}

>
You need to go PRO to post comments.

Lessons in Android Clean Architecture

1. Introduction to Clean Architecture
03:40
Joe Birch
GDE
2. Android and Clean Architecture
03:51
Joe Birch
GDE
3. Setting up a Multi-Module project
02:24
Joe Birch
GDE
4. Setting up the Domain layer module
02:24
Joe Birch
GDE
5. Creating the abstraction for our RxJava Observation Thread
02:02
Joe Birch
GDE
6. Setting up the Business Data for the Domain Layer
01:47
Joe Birch
GDE
7. Setting up the data access interface for the Domain Layer
01:49
Joe Birch
GDE
8. Setting up the Domain Layer Interactor classes
Pro
03:28
Joe Birch
GDE
9. Implementing the Get Projects use case
Pro
01:49
Joe Birch
GDE
10. Implementing the get Bookmarked Projects use case
Pro
01:33
Joe Birch
GDE
11. Implementing the Bookmark Project use case
Pro
01:57
Joe Birch
GDE
12. Implementing the UnBookmark Project use case (Domain layer 8)
Pro
02:03
Joe Birch
GDE
13. Testing the Get Projects use case
Pro
02:41
Joe Birch
GDE
14. Testing the Get Bookmarked Projects use case
Pro
02:04
Joe Birch
GDE
15. Testing the Bookmark Project use case
Pro
02:10
Joe Birch
GDE
16. Testing the UnBookmark Project use case
Pro
02:06
Joe Birch
GDE
17. Setting up the data module
Pro
02:17
Joe Birch
GDE
18. Creating the data models for the data layer
Pro
02:48
Joe Birch
GDE
19. Creating the external source interfaces for our data layer
Pro
02:24
Joe Birch
GDE
20. Creating the data layer store interface
Pro
01:19
Joe Birch
GDE
21. Creating the data layer cache data store
Pro
01:21
Joe Birch
GDE
22. Creating the data layer remote data store
Pro
01:39
Joe Birch
GDE
23. Creating the data store factory class
Pro
01:24
Joe Birch
GDE
24. Creating the central access point for the data layer
Pro
03:00
Joe Birch
GDE
25. Setting up the tests for the Data Layer
Pro
00:46
Joe Birch
GDE
26. Testing the data store factory class
Pro
01:39
Joe Birch
GDE
27. Testing the project entity mapper
Pro
01:18
Joe Birch
GDE
28. Testing the projects data repository
Pro
06:02
Joe Birch
GDE
29. Testing the projects cache data store
Pro
06:30
Joe Birch
GDE
30. Testing the projects remote data store
Pro
02:17
Joe Birch
GDE
31. Setting up the remote module
Pro
02:21
Joe Birch
GDE
32. Creating the data models for the remote layer
Pro
02:06
Joe Birch
GDE
33. Creating the Retrofit Service for the remote data source
Pro
01:58
Joe Birch
GDE
34. Creating the Retrofit Service Factory for the remote service interface
Pro
02:52
Joe Birch
GDE
35. Creating the data model mapper for the Remote Layer
Pro
01:59
Joe Birch
GDE
36. Creating the Remote Source implementation
Pro
01:55
Joe Birch
GDE
37. Setting up the Remote layer for testing
Pro
02:13
Joe Birch
GDE
38. Testing the remote model mapper class
Pro
01:39
Joe Birch
GDE
39. Testing the remote source implementation
Pro
05:09
Joe Birch
GDE
40. Setting up the Cache module
Pro
02:45
Joe Birch
GDE
41. Setting up the Cache layer data models
Pro
02:02
Joe Birch
GDE
42. Creating the database for the cache layer
Pro
01:34
Joe Birch
GDE
43. Creating the cached project Data Access Object
Pro
02:42
Joe Birch
GDE
44. Creating the Configuration Data Access Object
Pro
02:07
Joe Birch
GDE
45. Creating the cache model mapper
Pro
02:06
Joe Birch
GDE
46. Creating the Projects Cache data source Implementation
Pro
03:57
Joe Birch
GDE
47. Setting up the tests for our cache layer
Pro
01:17
Joe Birch
GDE
48. Testing the cached project model mapper
Pro
01:44
Joe Birch
GDE
49. Testing the Cached project DAO
Pro
04:33
Joe Birch
GDE
50. Testing the Configuration DAO
Pro
02:05
Joe Birch
GDE
51. Testing the projects cache implementation
Pro
05:48
Joe Birch
GDE
52. Setting up the presentation module
Pro
02:05
Joe Birch
GDE
53. Creating the data models for the presentation layer
Pro
01:13
Joe Birch
GDE
54. Creating the data model mapper for the presentation layer
Pro
01:26
Joe Birch
GDE
55. Creating the presentation state model
Pro
01:39
Joe Birch
GDE
56. Creating the browse projects view model
Pro
04:25
Joe Birch
GDE
57. Creating the bookmarked projects view model
Pro
03:05
Joe Birch
GDE
58. Setting up the presentation module tests
Pro
02:09
Joe Birch
GDE
59. Testing the view model mapper
Pro
01:17
Joe Birch
GDE
60. Testing our Browse Projects View Model implementation
Pro
04:36
Joe Birch
GDE
61. Testing our Browse Bookmarked Projects View Model implementation
Pro
04:34
Joe Birch
GDE
62. Setting up the UI module
Pro
02:22
Joe Birch
GDE
63. Creating the Post Execution Thread Implementation
Pro
01:26
Joe Birch
GDE
64. Setting up the application class
Pro
00:50
Joe Birch
GDE
65. Setting up the Dependency Injection for the UI module
Pro
02:46
Joe Birch
GDE
66. Creating the UI modules Project representation
Pro
00:50
Joe Birch
GDE
67. Creating the the Project model mapper for the UI module
Pro
01:24
Joe Birch
GDE
68. Setting up the Browse Projects Activity
Pro
01:08
Joe Birch
GDE
69. Configuring the DI for the project
Pro
04:37
Joe Birch
GDE
70. Creating the Project item view
Pro
01:51
Joe Birch
GDE
71. Creating the Browse Projects Adapter
Pro
03:27
Joe Birch
GDE
72. Creating the browse bookmarked projects adapter
Pro
03:54
Joe Birch
GDE
73. Creating the browse bookmarked projects activity
Pro
03:18
Joe Birch
GDE
74. Tying together the browse projects and bookmarked projects activity
Pro
02:30
Joe Birch
GDE
75. Setting up Unit Tests for the UI module
Pro
00:54
Joe Birch
GDE
76. Test the project model mapper
Pro
01:10
Joe Birch
GDE
77. Configuring the Dependency Injection for our User Interface tests
Pro
06:10
Joe Birch
GDE
78. Writing Espresso tests for the Browse Projects Activity
Pro
03:15
Joe Birch
GDE
79. Writing Espresso tests for the Bookmarked Projects Activity
Pro
02:34
Joe Birch
GDE
80. Simplifying the work we have done
Pro
05:14
Joe Birch
GDE