Extract generic test code

This commit is contained in:
Kirill Kamakin
2021-11-13 17:49:35 +03:00
parent dd74715818
commit 22d19b4c04
5 changed files with 73 additions and 61 deletions

View File

@@ -2,57 +2,42 @@ package gq.kirmanak.mealie.data.auth.impl
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.TEST_PASSWORD
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.TEST_TOKEN
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.TEST_USERNAME
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.body
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.enqueueSuccessfulAuthResponse
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.enqueueUnsuccessfulAuthResponse
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import org.junit.After
import org.junit.Before
import org.junit.Test import org.junit.Test
import retrofit2.HttpException import retrofit2.HttpException
import java.nio.charset.Charset
import javax.inject.Inject import javax.inject.Inject
@ExperimentalSerializationApi @ExperimentalSerializationApi
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@HiltAndroidTest @HiltAndroidTest
class AuthDataSourceImplTest : BaseTest() { class AuthDataSourceImplTest : MockServerTest() {
@Inject @Inject
lateinit var subject: AuthDataSourceImpl lateinit var subject: AuthDataSourceImpl
private lateinit var mockServer: MockWebServer
private lateinit var serverUrl: String
@Before
fun startMockServer() {
mockServer = MockWebServer().apply {
start()
}
serverUrl = mockServer.url("/").toString()
}
@After
fun stopMockServer() {
mockServer.shutdown()
}
@Test @Test
fun `when authentication is successful then token is correct`() = runBlocking { fun `when authentication is successful then token is correct`() = runBlocking {
enqueueSuccessfulResponse() mockServer.enqueueSuccessfulAuthResponse()
val token = subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl) val token = subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl)
assertThat(token).isEqualTo(TEST_TOKEN) assertThat(token).isEqualTo(TEST_TOKEN)
} }
@Test(expected = HttpException::class) @Test(expected = HttpException::class)
fun `when authentication isn't successful then throws`(): Unit = runBlocking { fun `when authentication isn't successful then throws`(): Unit = runBlocking {
enqueueUnsuccessfulResponse() mockServer.enqueueUnsuccessfulAuthResponse()
subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl) subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl)
} }
@Test @Test
fun `when authentication is requested then body is correct`() = runBlocking { fun `when authentication is requested then body is correct`() = runBlocking {
enqueueSuccessfulResponse() mockServer.enqueueSuccessfulAuthResponse()
subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl) subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl)
val body = mockServer.takeRequest().body() val body = mockServer.takeRequest().body()
assertThat(body).isEqualTo("username=$TEST_USERNAME&password=$TEST_PASSWORD") assertThat(body).isEqualTo("username=$TEST_USERNAME&password=$TEST_PASSWORD")
@@ -60,37 +45,10 @@ class AuthDataSourceImplTest : BaseTest() {
@Test @Test
fun `when authentication is requested then path is correct`() = runBlocking { fun `when authentication is requested then path is correct`() = runBlocking {
enqueueSuccessfulResponse() mockServer.enqueueSuccessfulAuthResponse()
subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl) subject.authenticate(TEST_USERNAME, TEST_PASSWORD, serverUrl)
val path = mockServer.takeRequest().path val path = mockServer.takeRequest().path
assertThat(path).isEqualTo("/api/auth/token") assertThat(path).isEqualTo("/api/auth/token")
} }
private fun RecordedRequest.body() = body.readString(Charset.defaultCharset())
private fun enqueueUnsuccessfulResponse() {
val response = MockResponse()
.setBody(UNSUCCESSFUL_AUTH_RESPONSE)
.setHeader("Content-Type", "application/json")
.setResponseCode(401)
mockServer.enqueue(response)
}
private fun enqueueSuccessfulResponse() {
val response = MockResponse()
.setBody(SUCCESSFUL_AUTH_RESPONSE)
.setHeader("Content-Type", "application/json")
.setResponseCode(200)
mockServer.enqueue(response)
}
companion object {
private const val TEST_USERNAME = "TEST_USERNAME"
private const val TEST_PASSWORD = "TEST_PASSWORD"
private const val TEST_TOKEN = "TEST_TOKEN"
private const val SUCCESSFUL_AUTH_RESPONSE =
"{\"access_token\":\"$TEST_TOKEN\",\"token_type\":\"TEST_TOKEN_TYPE\"}"
private const val UNSUCCESSFUL_AUTH_RESPONSE =
"{\"detail\":\"Unauthorized\"}"
}
} }

View File

@@ -0,0 +1,35 @@
package gq.kirmanak.mealie.data.auth.impl
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import java.nio.charset.Charset
object AuthImplTestData {
const val TEST_USERNAME = "TEST_USERNAME"
const val TEST_PASSWORD = "TEST_PASSWORD"
const val TEST_TOKEN = "TEST_TOKEN"
const val SUCCESSFUL_AUTH_RESPONSE =
"{\"access_token\":\"$TEST_TOKEN\",\"token_type\":\"TEST_TOKEN_TYPE\"}"
const val UNSUCCESSFUL_AUTH_RESPONSE =
"{\"detail\":\"Unauthorized\"}"
const val TEST_URL = "TEST_URL"
fun RecordedRequest.body() = body.readString(Charset.defaultCharset())
fun MockWebServer.enqueueUnsuccessfulAuthResponse() {
val response = MockResponse()
.setBody(UNSUCCESSFUL_AUTH_RESPONSE)
.setHeader("Content-Type", "application/json")
.setResponseCode(401)
enqueue(response)
}
fun MockWebServer.enqueueSuccessfulAuthResponse() {
val response = MockResponse()
.setBody(SUCCESSFUL_AUTH_RESPONSE)
.setHeader("Content-Type", "application/json")
.setResponseCode(200)
enqueue(response)
}
}

View File

@@ -2,12 +2,14 @@ package gq.kirmanak.mealie.data.auth.impl
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.TEST_TOKEN
import gq.kirmanak.mealie.data.auth.impl.AuthImplTestData.TEST_URL
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Test import org.junit.Test
import javax.inject.Inject import javax.inject.Inject
@HiltAndroidTest @HiltAndroidTest
class AuthStorageImplTest : BaseTest() { class AuthStorageImplTest : HiltRobolectricTest() {
@Inject @Inject
lateinit var subject: AuthStorageImpl lateinit var subject: AuthStorageImpl
@@ -37,10 +39,4 @@ class AuthStorageImplTest : BaseTest() {
fun `when reading url without storing data then returns null`() = runBlocking { fun `when reading url without storing data then returns null`() = runBlocking {
assertThat(subject.getBaseUrl()).isNull() assertThat(subject.getBaseUrl()).isNull()
} }
companion object {
private const val TEST_TOKEN = "TEST_TOKEN"
private const val TEST_URL = "TEST_URL"
}
} }

View File

@@ -10,7 +10,7 @@ import org.robolectric.annotation.Config
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@Config(application = HiltTestApplication::class) @Config(application = HiltTestApplication::class)
abstract class BaseTest { abstract class HiltRobolectricTest {
@get:Rule @get:Rule
var hiltRule = HiltAndroidRule(this) var hiltRule = HiltAndroidRule(this)

View File

@@ -0,0 +1,23 @@
package gq.kirmanak.mealie.data.auth.impl
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
abstract class MockServerTest : HiltRobolectricTest() {
lateinit var mockServer: MockWebServer
lateinit var serverUrl: String
@Before
fun startMockServer() {
mockServer = MockWebServer().apply {
start()
}
serverUrl = mockServer.url("/").toString()
}
@After
fun stopMockServer() {
mockServer.shutdown()
}
}