Skip to content

Commit

Permalink
Add Unit Test
Browse files Browse the repository at this point in the history
  • Loading branch information
Nhat Vu committed Dec 2, 2021
1 parent befbc48 commit 6db68b5
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
build
.gradle
15 changes: 14 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@ android {
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "com.fatherofapps.androidbase.CustomTestRunner"
}


android {
sourceSets {
String sharedTestDir = 'src/sharedTest/java'
test {
java.srcDirs += sharedTestDir
}
androidTest {
java.srcDirs += sharedTestDir
}
}
}

buildTypes {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.fatherofapps.androidbase

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner
import dagger.hilt.android.testing.HiltTestApplication


class CustomTestRunner : AndroidJUnitRunner() {

override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
43 changes: 43 additions & 0 deletions app/src/androidTest/java/com/fatherofapps/androidbase/HiltExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.fatherofapps.androidbase

import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import androidx.annotation.StyleRes
import androidx.core.util.Preconditions
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider

inline fun <reified T : Fragment> launchFragmentInHiltContainer(
fragmentArgs: Bundle? = null,
@StyleRes themeResId: Int = R.style.Theme_FatherOfApps,
fragmentFactory: FragmentFactory? = null,
crossinline action: Fragment.() -> Unit = {}
) {
val startActivityIntent = Intent.makeMainActivity(
ComponentName(
ApplicationProvider.getApplicationContext(),
HiltTestActivity::class.java
)
).putExtra( "androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY", themeResId)

ActivityScenario.launch<HiltTestActivity>(startActivityIntent).onActivity { activity ->
fragmentFactory?.let {
activity.supportFragmentManager.fragmentFactory = it
}
val fragment: Fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
Preconditions.checkNotNull(T::class.java.classLoader),
T::class.java.name
)

fragment.arguments = fragmentArgs
activity.supportFragmentManager
.beginTransaction()
.add(android.R.id.content, fragment, "")
.commitNow()

fragment.action()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.fatherofapps.androidbase.data.apis

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.fatherofapps.androidbase.common.Logger
import com.google.common.truth.Truth
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okio.buffer
import okio.source
import org.json.JSONObject
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory


@RunWith(AndroidJUnit4::class)
@ExperimentalCoroutinesApi
class CustomerApiTest {

@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()

private lateinit var mockServer: MockWebServer

private lateinit var countryAPI: CustomerAPI

@Before
fun setup() {
mockServer = MockWebServer()
mockServer.start()
val url = mockServer.url("/")
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val moshiConverter = MoshiConverterFactory.create(moshi)

val retrofit = Retrofit.Builder().addConverterFactory(moshiConverter)
.baseUrl(url)
.build()

countryAPI = retrofit.create(CustomerAPI::class.java)
}

@After
fun stopService() {
mockServer.shutdown()
}


private fun enqueueResponse(fileName: String, headers: Map<String, String> = emptyMap(), responseCode: Int = 200) {

val inputStream = javaClass.classLoader!!
.getResourceAsStream(fileName)

val source = inputStream.source().buffer()
val mockResponse = MockResponse()
mockResponse.setResponseCode(responseCode)
for ((key, value) in headers) {
mockResponse.addHeader(key, value)
}
mockServer.enqueue(
mockResponse
.setBody(source.readString(Charsets.UTF_8))
)
}


// @Test
// fun getListCountries_fail_returns_an_error() = runBlocking{
// enqueueResponse("countryapi/getListCountries_error.json",responseCode = 400)
//
// val response = countryAPI.getListCountries()
//
// Truth.assertThat(response.isSuccessful).isFalse()
//
// val data = response.errorBody()?.string() ?: ""
// Truth.assertThat(data).isNotNull()
// val jsonError = JSONObject(data)
// Truth.assertThat(jsonError.has("message")).isTrue()
// val message = jsonError.getString("message")
// Truth.assertThat(message).isEqualTo("Specified request cannot be processed.")
// }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"message": "Something"
}
11 changes: 11 additions & 0 deletions app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fatherofapps.androidbase">

<application>
<activity
android:name="com.fatherofapps.androidbase.HiltTestActivity"
android:exported="false" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.fatherofapps.androidbase

import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class HiltTestActivity : AppCompatActivity()
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.fatherofapps.androidbase

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.rules.TestWatcher
import org.junit.runner.Description

@ExperimentalCoroutinesApi
class MainCoroutineRule(val dispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()):
TestWatcher()
{
override fun starting(description: Description?) {
super.starting(description)
Dispatchers.setMain(dispatcher)
}

override fun finished(description: Description?) {
super.finished(description)
Dispatchers.resetMain()
dispatcher.cleanupTestCoroutines()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.fatherofapps.androidbase


import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody

object TestNetworkUtils {

fun createBody(code: Int, body: String): ResponseBody?{
return okhttp3.Response.Builder().code(code).protocol(Protocol.HTTP_1_1)
.message("fail").request(Request.Builder().url("http://localhost/").build()).body(
body.toResponseBody("application/json; charset=utf-8".toMediaType())
)
.build().body
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.fatherofapps.androidbase.data.repositories

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.fatherofapps.androidbase.MainCoroutineRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Rule


@ExperimentalCoroutinesApi
class CustomerRepositoryTest{
@get:Rule
var mainCoroutinesApi = MainCoroutineRule()

@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()

// @Before
// fun init() {
// cartService = Mockito.mock(CartService::class.java)
// appSharePreference = Mockito.mock(AppSharePreference::class.java)
// productService = Mockito.mock(ProductService::class.java)
//
// cartRepository =
// CartRepository(cartService, appSharePreference, productService, Dispatchers.Main)
// }
//
//
// @Test
// fun createEmptyCart_loggedIn_calls_createEmptyCartForCustomerOfCartService() =
// mainCoroutinesApi.dispatcher.runBlockingTest {
// DataLocal.IS_LOGGED_IN = true
// Mockito.`when`(cartService.createEmptyCartForCustomer())
// .thenReturn(NetworkResult.Success("0235"))
// cartRepository.createEmptyCart()
// Mockito.verify(cartService).createEmptyCartForCustomer()
// }
//@Test
//fun createEmptyCart_forCustomerFail_throwsAnException() =
// mainCoroutinesApi.dispatcher.runBlockingTest {
// DataLocal.IS_LOGGED_IN = true
// val exception = BaseNetworkException()
// Mockito.`when`(cartService.createEmptyCartForCustomer())
// .thenReturn(NetworkResult.Error(exception))
// try {
// cartRepository.createEmptyCart()
// } catch (e: Exception) {
// Truth.assertThat(e).isNotNull()
// }
// }


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.fatherofapps.androidbase.ui.home

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.fatherofapps.androidbase.MainCoroutineRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Assert.*
import org.junit.Rule

@ExperimentalCoroutinesApi
class HomeViewModelTest {
@get:Rule
var mainCoroutineRule = MainCoroutineRule()

@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()



// @Test
// fun fetchData_loading() = mainCoroutineRule.dispatcher.runBlockingTest {
// mainCoroutineRule.dispatcher.pauseDispatcher()
// Mockito.`when`(cartRepository.getCartItems()).thenReturn(getListCartItems())
// Mockito.`when`(cartRepository.getTotal()).thenReturn(getTotal())
// cartViewModel.fetchData()
// Truth.assertThat(cartViewModel.isLoading.getOrAwaitValue().getContentIfNotHandled())
// .isTrue()
// mainCoroutineRule.dispatcher.resumeDispatcher()
// Truth.assertThat(cartViewModel.isLoading.getOrAwaitValue().getContentIfNotHandled())
// .isFalse()
// }

}

0 comments on commit 6db68b5

Please sign in to comment.