Last active
March 25, 2021 16:03
-
-
Save sheerazam/cdaa24e13cf834499686ff5207b0da3c to your computer and use it in GitHub Desktop.
End to End Test using MockWebserver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.test.platform.app.InstrumentationRegistry | |
import okhttp3.mockwebserver.MockWebServer | |
import org.junit.After | |
import org.junit.Before | |
import org.koin.core.context.stopKoin | |
import org.koin.test.KoinTest | |
import java.io.BufferedReader | |
import java.io.Reader | |
abstract class BaseUITest : KoinTest { | |
/** | |
* For MockWebServer instance | |
*/ | |
lateinit var mockServer: MockWebServer | |
/** | |
* Default, let server be shut down | |
*/ | |
private var mShouldStart = false | |
@Before | |
open fun setUp() { | |
startMockServer(true) | |
} | |
/** | |
* Reads input file and converts to json | |
*/ | |
fun getJson(path: String): String { | |
var content: String = "" | |
val testContext = InstrumentationRegistry.getInstrumentation().context | |
val inputStream = testContext.assets.open(path) | |
val reader = BufferedReader(inputStream.reader() as Reader?) | |
reader.use { reader -> | |
content = reader.readText() | |
} | |
return content | |
} | |
/** | |
* Start Mockwebserver | |
*/ | |
private fun startMockServer(shouldStart: Boolean) { | |
if (shouldStart) { | |
mShouldStart = shouldStart | |
mockServer = MockWebServer() | |
mockServer.start(8080) | |
} | |
} | |
/** | |
* Stop Mockwebserver | |
*/ | |
private fun stopMockServer() { | |
if (mShouldStart) { | |
mockServer.shutdown() | |
} | |
} | |
fun <T> getValueFromResultModel(resultUIModel: ApiResultUIModel<T>?): T? { | |
return when (val result = resultUIModel?.showSuccess?.peek()) { | |
is Result.Success -> { | |
result.data | |
} | |
is Result.Error -> { | |
null | |
} | |
else -> null | |
} | |
} | |
@After | |
open fun tearDown() { | |
//Stop Mock server | |
stopMockServer() | |
//Stop Koin as well | |
stopKoin() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def mockwebserver_version = '4.1.0' | |
def coroutines_version = "1.3.7" | |
////////// -------- Testing --------- //////////// | |
implementation 'androidx.test.espresso:espresso-idling-resource:3.3.0' | |
androidTestImplementation('com.schibsted.spain:barista:3.9.0') { | |
exclude group: 'org.jetbrains.kotlin' // Only if you already use Kotlin in your project | |
} | |
androidTestImplementation "org.koin:koin-test:$koin_version" | |
androidTestImplementation "androidx.arch.core:core-testing:2.1.0" | |
androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockwebserver_version" | |
androidTestImplementation "androidx.fragment:fragment-testing:1.3.1" | |
androidTestImplementation 'androidx.test.ext:junit:1.1.2' | |
androidTestImplementation 'com.jakewharton.espresso:okhttp3-idling-resource:1.0.0' | |
androidTestImplementation "io.mockk:mockk-android:1.10.6" | |
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun clickOnChildViewWithId(id: Int): ViewAction { | |
return object : ViewAction { | |
override fun getConstraints(): Matcher<View>? { | |
return null | |
} | |
override fun getDescription(): String { | |
return "Click on a child view with specified id." | |
} | |
override fun perform(uiController: UiController, view: View) { | |
val v = view.findViewById<View>(id) as Button | |
v.performClick() | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object FileReader { | |
fun readStringFromFile(fileName: String): String { | |
try { | |
val inputStream = (InstrumentationRegistry.getInstrumentation().targetContext | |
.applicationContext).assets.open(fileName) | |
val builder = StringBuilder() | |
val reader = InputStreamReader(inputStream, "UTF-8") | |
reader.readLines().forEach { | |
builder.append(it) | |
} | |
return builder.toString() | |
} catch (e: IOException) { | |
throw e | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun typeTextInChildViewWithId(id: Int, textToBeTyped: String): ViewAction { | |
return object : ViewAction { | |
override fun getConstraints(): Matcher<View>? { | |
return null | |
} | |
override fun getDescription(): String { | |
return "Click on a child view with specified id." | |
} | |
override fun perform(uiController: UiController, view: View) { | |
val v = view.findViewById<View>(id) as EditText | |
v.setText(textToBeTyped) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.SystemClock | |
import android.util.Log | |
import androidx.arch.core.executor.testing.InstantTaskExecutorRule | |
import androidx.fragment.app.testing.launchFragmentInContainer | |
import androidx.test.espresso.Espresso.onView | |
import androidx.test.espresso.IdlingRegistry | |
import androidx.test.espresso.contrib.RecyclerViewActions | |
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription | |
import androidx.test.ext.junit.runners.AndroidJUnit4 | |
import androidx.test.platform.app.InstrumentationRegistry | |
import com.jakewharton.espresso.OkHttp3IdlingResource | |
import com.xwray.groupie.GroupieViewHolder | |
import com.xwray.groupie.Item | |
import io.mockk.MockKAnnotations | |
import junit.framework.Assert.assertTrue | |
import kotlinx.coroutines.ExperimentalCoroutinesApi | |
import kotlinx.coroutines.test.runBlockingTest | |
import okhttp3.mockwebserver.Dispatcher | |
import okhttp3.mockwebserver.MockResponse | |
import okhttp3.mockwebserver.RecordedRequest | |
import org.junit.Before | |
import org.junit.Rule | |
import org.junit.Test | |
import org.junit.runner.RunWith | |
import org.koin.android.ext.koin.androidContext | |
import org.koin.core.component.inject | |
import org.koin.core.context.startKoin | |
import java.net.HttpURLConnection | |
@RunWith(AndroidJUnit4::class) | |
class WebLeadTest : BaseUITest() { | |
val apiFactory: Apifactory by inject() | |
@get:Rule | |
var instantExecutorRule = InstantTaskExecutorRule() | |
@Before | |
override fun setUp() { | |
super.setUp() | |
MockKAnnotations.init(this) | |
val context = InstrumentationRegistry.getInstrumentation().targetContext | |
startKoin { | |
androidContext(context) | |
modules(generateTestAppComponent()) | |
} | |
IdlingRegistry.getInstance().register( | |
OkHttp3IdlingResource.create( | |
"okhttp", | |
apiFactory.vpClient | |
)) | |
} | |
@OptIn(ExperimentalCoroutinesApi::class) | |
@Test | |
fun testWebLeadShouldSendDataCorrectly() = runBlockingTest { | |
val scenario = launchFragmentInContainer<PropertyDetailsBottomSheetFragment>(themeResId = R.style.AppBaseTheme) | |
mockServer.dispatcher = object : Dispatcher() { | |
override fun dispatch(request: RecordedRequest): MockResponse { | |
return if (request.path?.contains("detailApi") == true) { | |
MockResponse() | |
.setResponseCode(HttpURLConnection.HTTP_OK) | |
.setBody(FileReader.readStringFromFile("firstApiResponse.json")) | |
} else { | |
MockResponse() | |
.setResponseCode(HttpURLConnection.HTTP_OK) | |
.setBody(FileReader.readStringFromFile("otherApiResponse.json")) | |
} | |
} | |
} | |
SystemClock.sleep(1000) | |
var propertyDetailsFragment: PropertyDetailsBottomSheetFragment? = null | |
scenario.onFragment { fragment -> | |
propertyDetailsFragment = fragment | |
fragment.myViewModel1.selectedProperty?.CD_MLS = "1234" | |
advanceTimeBy(5000) | |
} | |
advanceTimeBy(5000) | |
assertTrue(propertyDetailsFragment != null) | |
assertTrue(propertyDetailsFragment?.group?.differ?.currentList?.isNotEmpty() == true) | |
val itemFirstName = propertyDetailsFragment?.group?.differ?.currentList?.first { | |
it.id.toString() == "cell_id1" | |
} | |
assertTrue(itemFirstName != null) | |
typeTextInRecyclerView(fragment = propertyDetailsFragment!!, | |
text = "Sheeraz", item = itemFirstName!!, editTextId = R.id.txtText) | |
val itemLastName = propertyDetailsFragment?.group?.differ?.currentList?.first { | |
it.id.toString() == "cell_id1" | |
} | |
assertTrue(itemLastName != null) | |
typeTextInRecyclerView(fragment = propertyDetailsFragment!!, | |
text = "Ahmed", item = itemLastName!!, editTextId = R.id.txtText) | |
val itemEmail = propertyDetailsFragment?.group?.differ?.currentList?.first { | |
it.id.toString() == "cell_id2" | |
} | |
assertTrue(itemEmail != null) | |
typeTextInRecyclerView(fragment = propertyDetailsFragment!!, | |
text = "[email protected]", item = itemEmail!!, editTextId = R.id.txtText) | |
val itemNotes = propertyDetailsFragment?.group?.differ?.currentList?.first { | |
it.id.toString() == "cell_id3" | |
} | |
assertTrue(itemNotes != null) | |
typeTextInRecyclerView(fragment = propertyDetailsFragment!!, | |
text = "test notes", item = itemNotes!!, editTextId = R.id.txtText) | |
val itemSendButton = propertyDetailsFragment?.group?.differ?.currentList?.first { | |
it.id.toString() == "cell_id4" | |
} | |
clickOnSendButton(fragment = propertyDetailsFragment!!, item = itemSendButton!!) | |
SystemClock.sleep(2000) | |
val value = propertyDetailsFragment?.myViewModel2?.sendMeInfoState?.getOrAwaitValue() | |
advanceTimeBy(5000) | |
assertTrue(getValueFromResultModel(value)?.CELLS?.isNotEmpty() == true) | |
Log.d("PropertyTest", mockServer.takeRequest().requestLine) | |
val requestData = mockServer.takeRequest().body.readUtf8Line()!! | |
Log.d("PropertyTest", requestData) | |
assertTrue(requestData.contains("CC_FIRSTNAME=Sheeraz")) | |
assertTrue(requestData.contains("CC_LASTNAME=Ahmed")) | |
assertTrue(requestData.contains("cd_MLS=1234")) | |
assertTrue(requestData.contains("[email protected]")) | |
assertTrue(requestData.contains("CI_DS_NOTES=test%20notes")) | |
assertTrue(requestData.contains("CI_MLS_NUMBER=12345")) | |
assertTrue(requestData.contains("IS_SHOWING=")) | |
} | |
fun typeTextInRecyclerView(fragment: PropertyDetailsBottomSheetFragment, text: String, editTextId: Int, item: Item<GroupieViewHolder>) { | |
val context = InstrumentationRegistry.getInstrumentation().targetContext | |
onView(withContentDescription(context.resources.getString(R.string.property_details_main_recycler_view))) | |
.perform(RecyclerViewActions | |
.actionOnItemAtPosition<GroupieViewHolder>(fragment.group.getPosition(item), | |
typeTextInChildViewWithId(editTextId, text))) | |
} | |
fun clickOnSendButton(fragment: PropertyDetailsBottomSheetFragment, item: Item<GroupieViewHolder>) { | |
val context = InstrumentationRegistry.getInstrumentation().targetContext | |
onView(withContentDescription(context.resources.getString(R.string.property_details_main_recycler_view))) | |
.perform(RecyclerViewActions | |
.actionOnItemAtPosition<GroupieViewHolder>(fragment.group.getPosition(item), | |
clickOnChildViewWithId(R.id.button))) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment