Skip to content

Commit

Permalink
STEP 9 : write integration tests to check our screens
Browse files Browse the repository at this point in the history
  • Loading branch information
javamind committed Apr 10, 2019
1 parent a0e8295 commit 6c4d841
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 24 deletions.

This file was deleted.

24 changes: 24 additions & 0 deletions app/src/androidTest/java/com/devmind/devoxx/MainActivityTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.devmind.devoxx

import androidx.test.espresso.Espresso
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import androidx.test.rule.ActivityTestRule
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4ClassRunner::class)
class MainActivityTest{

@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)

@Test
fun shouldDisplayTitle(){
Espresso.onView(ViewMatchers.withId(R.id.title))
.check(ViewAssertions.matches(ViewMatchers.withText(R.string.app_name)))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.devmind.devoxx

import androidx.arch.core.executor.testing.CountingTaskExecutorRule
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import com.devmind.devoxx.model.Speaker
import com.devmind.devoxx.model.SpeakerAdapter
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.TimeUnit


@RunWith(AndroidJUnit4ClassRunner::class)
class SpeakerListActivityTest {

@get:Rule
val activityRule = ActivityTestRule<SpeakerListActivity>(SpeakerListActivity::class.java, false, false)

@get:Rule
val countingTaskExecutorRule = CountingTaskExecutorRule()

constructor() {
val application =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as DevoxxApplication
application.deleteDatabase("devoxx2")
val dao = application.speakerDao()
if (dao.readAll().isEmpty()) {
dao.create(Speaker("Romain", "Guy"))
dao.create(Speaker("Chet", "Haase"))
}
}

@Before
fun init() {
activityRule.launchActivity(null)
}

@Test
fun shouldDisplaySpeakers() {
drain()
Espresso.onView(ViewMatchers.withText("Romain Guy")).check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Espresso.onView(ViewMatchers.withText("Chet Haase")).check(ViewAssertions.matches(ViewMatchers.isDisplayed()))

}

@Test
fun shouldCreateSpeaker() {
drain()
Espresso.onView(ViewMatchers.withId(R.id.buttonAddSpeaker)).perform(ViewActions.click())
// After this click we should be on speaker view in creation mode
Espresso.onView(ViewMatchers.withId(R.id.speakerFirstname)).check(ViewAssertions.matches(ViewMatchers.withText("")))
Espresso.onView(ViewMatchers.withId(R.id.speakerLastname)).check(ViewAssertions.matches(ViewMatchers.withText("")))
}

@Test
fun shouldUpdateSpeaker() {
drain()
Espresso.onView(ViewMatchers.withId(R.id.speakerList)).perform(
RecyclerViewActions.actionOnItemAtPosition<SpeakerAdapter.ViewHolder>(0, ViewActions.click()))
// After this click we should be on speaker view in update mode
Espresso.onView(ViewMatchers.withId(R.id.speakerFirstname)).check(ViewAssertions.matches(ViewMatchers.withText("Romain")))
Espresso.onView(ViewMatchers.withId(R.id.speakerLastname)).check(ViewAssertions.matches(ViewMatchers.withText("Guy")))
}

fun drain() {
countingTaskExecutorRule.drainTasks(1, TimeUnit.MINUTES)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.devmind.devoxx

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import com.devmind.devoxx.model.Speaker
import com.devmind.devoxx.model.SpeakerDao
import com.google.common.truth.Truth
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4ClassRunner::class)
class SpeakerListViewModelTest {

/**
* Swaps background executor used by the Architecture Components with a different one which executes
* each task synchronously.
*/
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

lateinit var viewModel: SpeakerListViewModel
lateinit var speakerDao: SpeakerDao
lateinit var observer: Observer<List<Speaker>>


@Before
fun onInit() {
speakerDao = mockk(relaxUnitFun = true)
observer = mockk(relaxed = true)

val devoxxApplication = mockk<DevoxxApplication>(){
every { speakerDao() } returns speakerDao
}
viewModel = SpeakerListViewModel(devoxxApplication)
}

@After
fun onTearDown(){
viewModel.speakersLiveData.removeObserver(observer)
}

@Test
fun shouldLoadSpeakers() {
val speakers = arrayListOf(Speaker("Romain", "Guy"))
every { speakerDao.readAll() } returns speakers

viewModel.speakersLiveData.observeForever(observer)

verify { speakerDao.readAll() }
verify { observer.onChanged(any()) }
}
}
104 changes: 104 additions & 0 deletions app/src/androidTest/java/com/devmind/devoxx/SpeakerViewModelTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.devmind.devoxx

import androidx.arch.core.executor.testing.CountingTaskExecutorRule
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import com.devmind.devoxx.model.Speaker
import com.devmind.devoxx.model.SpeakerDao
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.TimeUnit


@RunWith(AndroidJUnit4ClassRunner::class)
class SpeakerViewModelTest {

/**
* Swaps background executor used by the Architecture Components with a different one which executes
* each task synchronously.
*/
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

// @get:Rule
// val countingTaskExecutorRule = CountingTaskExecutorRule()

lateinit var viewModel: SpeakerViewModel
lateinit var speakerDao: SpeakerDao
lateinit var observer: Observer<Speaker>


@Before
fun onInit() {
speakerDao = mockk(relaxUnitFun = true)
observer = mockk(relaxed = true)

val devoxxApplication = mockk<DevoxxApplication>(){
every { speakerDao() } returns speakerDao
}
viewModel = SpeakerViewModel(devoxxApplication)
}

@After
fun onTearDown(){
viewModel.speakerLiveData.removeObserver(observer)
}

@Test
fun shouldLoadSpeaker() {
val speaker = Speaker("Romain", "Guy")

every { speakerDao.readOne(speaker.uuid) } returns speaker

instantTaskExecutorRule.run {
viewModel.speakerLiveData.observeForever(observer)
viewModel.loadSpeaker(speaker.uuid)

drain()
verify { speakerDao.readOne(speaker.uuid) }
verify { observer.onChanged(speaker) }
}
}

@Test
fun shouldSaveSpeaker() {
val speaker = Speaker("Romain", "Guy")

instantTaskExecutorRule.run {
viewModel.speakerLiveData.observeForever(observer)
viewModel.createSpeaker(speaker)

drain()
verify { speakerDao.create(speaker) }
verify { observer.onChanged(speaker) }
}
}

@Test
fun shouldUpdateSpeaker() {
val speaker = Speaker("Romain", "Guy")

instantTaskExecutorRule.run {
viewModel.speakerLiveData.observeForever(observer)
viewModel.updateSpeaker(speaker)

verify { speakerDao.update(speaker) }
verify { observer.onChanged(speaker) }
}
drain()
// verify { speakerDao.update(speaker) }
// verify { observer.onChanged(speaker) }
}

fun drain(){
instantTaskExecutorRule.run { }
// countingTaskExecutorRule.drainTasks(1, TimeUnit.MINUTES)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.devmind.devoxx.model

import androidx.room.Room
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4ClassRunner::class)
class SpeakerDaoTest{

lateinit var database: DevoxxDatabase
lateinit var dao: SpeakerDao
private val speaker = Speaker("Chet", "Haase", "USA")

@Before
fun onInit(){
val testContext = InstrumentationRegistry.getInstrumentation().context

database = Room.inMemoryDatabaseBuilder(testContext, DevoxxDatabase::class.java).allowMainThreadQueries().build()
dao = database.speakerDao()
dao.create(speaker)
}

@After
fun onClose() = database.close()

@Test
fun readAll(){
val speakers = dao.readAll()
Truth.assertThat(speakers).containsExactly(speaker)
}

@Test
fun readOne(){
val speaker = dao.readOne(speaker.uuid)
Truth.assertThat(speaker).isEqualTo(speaker)
}

@Test
fun readOneByUnknownId(){
val speaker = dao.readOne("unknown")
Truth.assertThat(speaker).isNull()
}

@Test
fun update(){
dao.update(Speaker("Chet", "Guy", "USA", speaker.uuid))
val speaker = dao.readOne(speaker.uuid)
Truth.assertThat(speaker.lastname).isEqualTo("Guy")
}

@Test
fun delete(){
dao.delete(speaker)
val speakers = dao.readAll()
Truth.assertThat(speakers).isEmpty()
}
}

0 comments on commit 6c4d841

Please sign in to comment.