-
Notifications
You must be signed in to change notification settings - Fork 56
Unit Tests improvements #137
base: main
Are you sure you want to change the base?
Changes from 4 commits
fde5b1e
f18d3f6
c60b401
0149805
9480825
74d9471
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -84,6 +84,9 @@ kotlin { | |
| languageSettings.apply { | ||
| optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") | ||
| } | ||
| dependencies { | ||
| implementation("com.google.truth:truth:1.0.1") | ||
| } | ||
|
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,5 +23,5 @@ import com.android254.data.db.model.Session | |
| interface SessionDao : BaseDao<Session> { | ||
|
|
||
| @Query("SELECT * FROM SESSION") | ||
| fun fetchSessions(): List<Session> | ||
| suspend fun fetchSessions(): List<Session> // This should be suspended or return FLow [Note: Don't suspend Flows] | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ import kotlinx.coroutines.flow.Flow | |
|
|
||
| interface TokenProvider { | ||
|
|
||
| suspend fun fetch(): Flow<String?> | ||
| suspend fun fetch(): Flow<String?> // @Allan -> Don't suspend Flows | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove comment. We can add it to the readme instead.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anselmoalexandre Good catch Remove the suspend and return a flow 👯
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @chepsi
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anselmoalexandre saw it I can raise a PR, but if you want, please feel free to refactor it here
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You can do the PR it's okay 👌🏿. Also, this was only heads up 😄 |
||
|
|
||
| suspend fun update(accessToken: String) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,51 +15,44 @@ | |
| */ | ||
| package com.android254.data.dao | ||
|
|
||
| import android.content.Context | ||
| import androidx.room.Room | ||
| import androidx.test.core.app.ApplicationProvider | ||
| import com.android254.data.db.Database | ||
| import com.android254.data.db.model.Session | ||
| import com.google.common.truth.Truth | ||
| import io.mockk.* | ||
| import io.mockk.impl.annotations.MockK | ||
| import kotlinx.coroutines.test.runTest | ||
| import kotlinx.datetime.toInstant | ||
| import org.hamcrest.CoreMatchers.`is` | ||
| import org.hamcrest.MatcherAssert.assertThat | ||
| import org.junit.After | ||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
| import org.robolectric.RobolectricTestRunner | ||
| import java.io.IOException | ||
|
|
||
| @RunWith(RobolectricTestRunner::class) | ||
| class SessionDaoTest { | ||
|
|
||
| private lateinit var session: Session | ||
| @MockK | ||
| private lateinit var sessionDao: SessionDao | ||
| private lateinit var db: Database | ||
|
Comment on lines
-35
to
-39
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are using Robolectric because we want to test against a real db.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @michaelbukachi With robolectric: it slows down the tests a lot, but it's sometimes helpful if we really want to test the integration with the Android system
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest to use it only in a few places, not everywhere. Considering that tests performance are also very important and should be fast as possible
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But it's okay if you guys think you want to stick with this.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anselmoalexandre We are aware of its drawbacks. We used it to ensure all our queries were running as expected. |
||
|
|
||
| @Before | ||
| fun setup() { | ||
| val context = ApplicationProvider.getApplicationContext<Context>() | ||
| db = Room.inMemoryDatabaseBuilder( | ||
| context, | ||
| Database::class.java | ||
| MockKAnnotations.init(this, relaxUnitFun = true) | ||
| session = Session( | ||
| id = 0, | ||
| name = "Welcome Keynote", | ||
| publishDate = "2010-06-01T22:19:44.475Z".toInstant() | ||
| ) | ||
| .allowMainThreadQueries() // TODO Please delete me | ||
| .build() | ||
| sessionDao = db.sessionDao() | ||
| } | ||
|
|
||
| @After | ||
| @Throws(IOException::class) | ||
| fun tearDown() { | ||
| db.close() | ||
| coJustRun { sessionDao.insert(session) } | ||
| coEvery { sessionDao.fetchSessions() } returns listOf(session) | ||
| } | ||
|
|
||
| @Test | ||
| fun `test sessionDao fetches all sessions`() = runTest { | ||
| val session = Session(0, "Welcome Keynote", "2010-06-01T22:19:44.475Z".toInstant()) | ||
| // Given | ||
| sessionDao.insert(session) | ||
| val result = sessionDao.fetchSessions().first() | ||
| assertThat(session.name, `is`(result.name)) | ||
|
|
||
| // When | ||
| val result = sessionDao.fetchSessions().first().name | ||
|
|
||
| // Then | ||
| coVerify(atLeast = 1) { sessionDao.insert(session) } | ||
| coVerify { sessionDao.insert(session) } | ||
| Truth.assertThat(result).isEqualTo(session.name) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,12 +29,11 @@ import com.android254.data.network.models.responses.UserDetails | |
| import com.android254.data.network.util.HttpClientFactory | ||
| import com.android254.data.network.util.ServerError | ||
| import com.android254.data.preferences.DefaultTokenProvider | ||
| import com.google.common.truth.Truth | ||
| import io.ktor.client.engine.mock.* | ||
| import io.ktor.http.* | ||
| import kotlinx.coroutines.delay | ||
| import kotlinx.coroutines.runBlocking | ||
| import org.hamcrest.CoreMatchers.`is` | ||
| import org.hamcrest.MatcherAssert.assertThat | ||
| import kotlinx.coroutines.test.runTest | ||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
|
|
@@ -55,19 +54,21 @@ class AuthApiTest { | |
|
|
||
| @Test(expected = ServerError::class) | ||
| fun `test ServerError is thrown when a server exception occurs`() { | ||
| // Given | ||
| val mockEngine = MockEngine { | ||
| delay(500) | ||
| respondError(HttpStatusCode.InternalServerError) | ||
| } | ||
| val httpClient = HttpClientFactory(DefaultTokenProvider(testDataStore)).create(mockEngine) | ||
| val api = AuthApi(httpClient) | ||
| runBlocking { | ||
| api.logout() | ||
| } | ||
|
|
||
| // When | ||
| runTest { api.logout() } | ||
| } | ||
|
|
||
| @Test | ||
| fun `test successful logout`() { | ||
| // Given | ||
| val mockEngine = MockEngine { | ||
| respond( | ||
| content = """{"message": "Success"}""", | ||
|
|
@@ -77,14 +78,18 @@ class AuthApiTest { | |
| } | ||
| val httpClient = HttpClientFactory(DefaultTokenProvider(testDataStore)).create(mockEngine) | ||
| val api = AuthApi(httpClient) | ||
| runBlocking { | ||
| val response = api.logout() | ||
| assertThat(response, `is`(Status("Success"))) | ||
|
|
||
| // Then | ||
| runTest { | ||
| api.logout().also { | ||
| Truth.assertThat(it).isEqualTo(Status("Success")) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun `test successful google login`() { | ||
| // Given | ||
| val content = """ | ||
| { | ||
| "token": "test", | ||
|
|
@@ -106,18 +111,23 @@ class AuthApiTest { | |
| } | ||
| val httpClient = HttpClientFactory(DefaultTokenProvider(testDataStore)).create(mockEngine) | ||
| val api = AuthApi(httpClient) | ||
| runBlocking { | ||
| val accessToken = AccessToken( | ||
| token = "test", | ||
| user = UserDetails( | ||
| name = "Magak Emmanuel", | ||
| email = "[email protected]", | ||
| gender = null, | ||
| avatar = "http://localhost:8000/upload/avatar/img-20181016-wa0026jpg.jpg" | ||
| ) | ||
|
|
||
| val accessToken = AccessToken( | ||
| token = "test", | ||
| user = UserDetails( | ||
| name = "Magak Emmanuel", | ||
| email = "[email protected]", | ||
| gender = null, | ||
| avatar = "http://localhost:8000/upload/avatar/img-20181016-wa0026jpg.jpg" | ||
| ) | ||
| val response = api.googleLogin(GoogleToken("some token")) | ||
| assertThat(response, `is`(accessToken)) | ||
| ) | ||
|
|
||
| // Then | ||
| runTest { | ||
| api.googleLogin(GoogleToken("some token")).also { | ||
| Truth.assertThat(it).isEqualTo(accessToken) | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @anselmoalexandre For all dependencies, you need to add them to the
lib.versions file. You can check the Readme on why we do this.Great PR!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦🏿♂️ my bad. Let me add it to version catalog
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Added the dependency to
lib.versionsfile