From f312106e01e1d7136f32f524e82f18ecaa6a792b Mon Sep 17 00:00:00 2001 From: adammc331 Date: Wed, 30 Jan 2019 20:50:48 -0500 Subject: [PATCH] Added a helper class for mocking firebase data for #138. --- Droidcon-Boston/app/build.gradle | 2 + .../droidcon_boston/data/Schedule.kt | 12 +++--- .../firebase/FirebaseHelper.kt | 27 ++++++------ .../firebase/FirebaseHelperRobot.kt | 43 +++++++++++++++++++ .../views/detail/AgendaDetailViewModelTest.kt | 32 ++++++++++++-- 5 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelperRobot.kt diff --git a/Droidcon-Boston/app/build.gradle b/Droidcon-Boston/app/build.gradle index a2bd804..71e274f 100644 --- a/Droidcon-Boston/app/build.gradle +++ b/Droidcon-Boston/app/build.gradle @@ -102,6 +102,7 @@ dependencies { final threeTenAbp = '1.0.5' final recyclerRefreshLayout = '2.0.5' final mockitoCore = '2.23.4' + final archCore = '2.0.0' //endregion //region Dependencies @@ -112,6 +113,7 @@ dependencies { testImplementation "junit:junit:$junit" testImplementation "org.threeten:threetenbp:$threeTen" testImplementation "org.mockito:mockito-core:$mockitoCore" + testImplementation "androidx.arch.core:core-testing:$archCore" // Support implementation "androidx.appcompat:appcompat:$appCompat" diff --git a/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/data/Schedule.kt b/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/data/Schedule.kt index 21e1b88..1456c5d 100644 --- a/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/data/Schedule.kt +++ b/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/data/Schedule.kt @@ -31,13 +31,13 @@ class Schedule { fun getSpeakerString(): String? = speakerNames.joinToString(", ") } - class ScheduleDetail(val listRow: ScheduleRow) { - - var speakerBio: String = "" - var twitter: String = "" - var linkedIn: String = "" + data class ScheduleDetail( + val listRow: ScheduleRow, + var speakerBio: String = "", + var twitter: String = "", + var linkedIn: String = "", var facebook: String = "" - + ) { val id: String get() = listRow.id } diff --git a/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelper.kt b/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelper.kt index 1c4e2f6..f104a8c 100644 --- a/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelper.kt +++ b/Droidcon-Boston/app/src/main/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelper.kt @@ -7,25 +7,22 @@ import com.google.firebase.database.FirebaseDatabase open class FirebaseHelper private constructor() { private val database: FirebaseDatabase = FirebaseDatabase.getInstance() - private val mainDatabase: DatabaseReference - val eventDatabase: DatabaseReference - val speakerDatabase: DatabaseReference - val aboutDatabase: DatabaseReference - val faqDatabase: DatabaseReference - val cocDatabase: DatabaseReference - val volunteerDatabase: DatabaseReference + private val mainDatabase: DatabaseReference = database.reference - init { + open val eventDatabase: DatabaseReference = + mainDatabase.child("conferenceData").child("events") + + open val speakerDatabase: DatabaseReference = + mainDatabase.child("conferenceData").child("speakers") + open val aboutDatabase: DatabaseReference = mainDatabase.child("about") + open val faqDatabase: DatabaseReference = mainDatabase.child("faq") + open val cocDatabase: DatabaseReference = mainDatabase.child("conductCode") + open val volunteerDatabase: DatabaseReference = mainDatabase.child("volunteers") + + init { // Enable disk persistence, https://firebase.google.com/docs/database/android/offline-capabilities this.database.setPersistenceEnabled(true) - this.mainDatabase = database.reference - this.eventDatabase = mainDatabase.child("conferenceData").child("events") - this.speakerDatabase = mainDatabase.child("conferenceData").child("speakers") - this.volunteerDatabase = mainDatabase.child("volunteers") - this.aboutDatabase = mainDatabase.child("about") - this.faqDatabase = mainDatabase.child("faq") - this.cocDatabase = mainDatabase.child("conductCode") } private object Holder { diff --git a/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelperRobot.kt b/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelperRobot.kt new file mode 100644 index 0000000..50a8999 --- /dev/null +++ b/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/firebase/FirebaseHelperRobot.kt @@ -0,0 +1,43 @@ +package com.mentalmachines.droidcon_boston.firebase + +import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseReference +import com.google.firebase.database.ValueEventListener +import com.mentalmachines.droidcon_boston.data.FirebaseDatabase +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito.* + +/** + * A robot class that can be used to extract out firebase functionality from the tests. + * + * Mainly we can use this to extract mocking. + */ +class FirebaseHelperRobot(mockFirebaseHelper: FirebaseHelper) { + private val mockSpeakerReference = mock(DatabaseReference::class.java) + + init { + `when`(mockFirebaseHelper.speakerDatabase).thenReturn(mockSpeakerReference) + `when`(mockSpeakerReference.orderByChild(anyString())).thenReturn(mockSpeakerReference) + } + + fun mockSpeakers(speakers: List): FirebaseHelperRobot { + val speakerSnapshots = speakers.map { speaker -> + val mockSnapshot = mock(DataSnapshot::class.java) + `when`(mockSnapshot.getValue(FirebaseDatabase.EventSpeaker::class.java)).thenReturn( + speaker + ) + return@map mockSnapshot + } + + val mockSnapshot = mock(DataSnapshot::class.java) + `when`(mockSnapshot.children).thenReturn(speakerSnapshots) + + doAnswer { + val valueEventListener = it.arguments.first() as ValueEventListener + valueEventListener.onDataChange(mockSnapshot) + return@doAnswer null + }.`when`(mockSpeakerReference).addValueEventListener(any(ValueEventListener::class.java)) + + return this + } +} \ No newline at end of file diff --git a/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/views/detail/AgendaDetailViewModelTest.kt b/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/views/detail/AgendaDetailViewModelTest.kt index 69a0a29..24e1b83 100644 --- a/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/views/detail/AgendaDetailViewModelTest.kt +++ b/Droidcon-Boston/app/src/test/java/com/mentalmachines/droidcon_boston/views/detail/AgendaDetailViewModelTest.kt @@ -1,12 +1,20 @@ package com.mentalmachines.droidcon_boston.views.detail +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseReference +import com.google.firebase.database.ValueEventListener +import com.mentalmachines.droidcon_boston.data.FirebaseDatabase import com.mentalmachines.droidcon_boston.data.Schedule import com.mentalmachines.droidcon_boston.data.UserAgendaRepo import com.mentalmachines.droidcon_boston.firebase.FirebaseHelper +import com.mentalmachines.droidcon_boston.firebase.FirebaseHelperRobot import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse +import org.junit.Rule import org.junit.Test -import org.mockito.Mockito.mock +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito.* class AgendaDetailViewModelTest { private val mockAgendaRepo = mock(UserAgendaRepo::class.java) @@ -16,7 +24,9 @@ class AgendaDetailViewModelTest { private val startTime = "2018-03-26T15:00:00.000Z" private val endTime = "2018-03-26T15:45:00.000Z" private val scheduleId = "Schedule ID" - private val speakerNames = listOf("John", "Bob") + private val primarySpeakerName = "John" + private val secondarySpeakerName = "Bob" + private val speakerNames = listOf(primarySpeakerName, secondarySpeakerName) private val scheduleRow = Schedule.ScheduleRow( talkTitle = talkTitle, @@ -24,11 +34,16 @@ class AgendaDetailViewModelTest { startTime = startTime, endTime = endTime, id = scheduleId, - speakerNames = speakerNames + speakerNames = speakerNames, + primarySpeakerName = primarySpeakerName ) private val viewModel = AgendaDetailViewModel(scheduleRow, mockAgendaRepo, mockFirebaseHelper) + @JvmField + @Rule + val instantTaskExecutor = InstantTaskExecutorRule() + @Test fun getTalkTitle() { assertEquals(talkTitle, viewModel.talkTitle) @@ -63,4 +78,15 @@ class AgendaDetailViewModelTest { fun bookmarkedWithoutSession() { assertFalse(viewModel.isBookmarked) } + + @Test + fun loadData() { + val eventSpeaker = FirebaseDatabase.EventSpeaker(name = primarySpeakerName) + FirebaseHelperRobot(mockFirebaseHelper).mockSpeakers(listOf(eventSpeaker)) + + viewModel.loadData() + + val scheduleDetail = eventSpeaker.toScheduleDetail(scheduleRow) + assertEquals(scheduleDetail, viewModel.scheduleDetail.value) + } } \ No newline at end of file