add automated android tests
This commit is contained in:
parent
8130012710
commit
9fc3c124bf
@ -25,6 +25,16 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -39,9 +49,26 @@ dependencies {
|
||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.0"
|
||||
implementation 'com.jakewharton.rxbinding2:rxbinding:2.2.0'
|
||||
implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.2.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
|
||||
androidTestImplementation 'androidx.test:core-ktx:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
androidTestImplementation 'androidx.test:runner:' + rootProject.runnerVersion
|
||||
androidTestImplementation 'androidx.test:rules:' + rootProject.rulesVersion
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-intents:' + rootProject.espressoVersion
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-contrib:' + rootProject.espressoVersion
|
||||
androidTestImplementation 'androidx.test.ext:truth:' + rootProject.extTruthVersion
|
||||
androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
androidTestImplementation 'org.robolectric:annotations:' + rootProject.robolectricVersion
|
||||
|
||||
testImplementation 'androidx.test:core:' + rootProject.coreVersion
|
||||
testImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
testImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
|
||||
testImplementation 'androidx.test.espresso:espresso-intents:' + rootProject.espressoVersion
|
||||
testImplementation 'androidx.test.espresso:espresso-contrib:' + rootProject.espressoVersion
|
||||
testImplementation 'androidx.test.ext:truth:' + rootProject.extTruthVersion
|
||||
testImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
testImplementation 'org.robolectric:robolectric:' + rootProject.robolectricVersion
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.core.app.launchActivity
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.actionOnChild
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.cleanLocalStorage
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.AddSocialActivity
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AddSocialActivityTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activity = IntentsTestRule(AddSocialActivity::class.java)
|
||||
|
||||
|
||||
@Test
|
||||
fun initialState_noAddedSocials_oneAvailableSocial() {
|
||||
cleanLocalStorage(activity)
|
||||
|
||||
val newActivity = launchActivity<AddSocialActivity>()
|
||||
|
||||
assertEquals(
|
||||
0, activity.activity.findViewById<RecyclerView>(R.id.availableSocialsRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
assertEquals(
|
||||
1, activity.activity.findViewById<RecyclerView>(R.id.addSocialRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clickingSocials_movesThemFormAvailableToAdded_etViceVersa() {
|
||||
cleanLocalStorage(activity)
|
||||
|
||||
onView(withId(R.id.addSocialRecyclerView))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
actionOnChild(click(), R.id.socialPlatformImage)
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
1, activity.activity.findViewById<RecyclerView>(R.id.availableSocialsRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
assertEquals(
|
||||
0, activity.activity.findViewById<RecyclerView>(R.id.addSocialRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
|
||||
onView(withId(R.id.availableSocialsRecyclerView))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
actionOnChild(click(), R.id.socialPlatformImage)
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
0, activity.activity.findViewById<RecyclerView>(R.id.availableSocialsRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
assertEquals(
|
||||
1, activity.activity.findViewById<RecyclerView>(R.id.addSocialRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -15,10 +15,12 @@ import org.junit.Assert.*
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
appContext.filesDir.delete()
|
||||
assertEquals("pl.edu.amu.wmi.socialaggregator", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.intent.Intents.intended
|
||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.AddSocialActivity
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.MainActivity
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.NewPostActivity
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MainActivityTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activity = IntentsTestRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun clickAddNewSocial_shouldOpenAddNewSocialActivity() {
|
||||
onView(withId(R.id.connectedSocialsButton)).perform(click())
|
||||
|
||||
intended(hasComponent(AddSocialActivity::class.java.name))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clickCreatePost_shouldOpenAddNewNewPostActivity() {
|
||||
onView(withId(R.id.createPostButton)).perform(click())
|
||||
|
||||
intended(hasComponent(NewPostActivity::class.java.name))
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.Espresso.*
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.atPosition
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.cleanLocalStorage
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.getCurrentActivity
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.MainActivity
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NewPostActivityTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activity = IntentsTestRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun clickPublishPost_shouldEndActivity() {
|
||||
onView(withId(R.id.createPostButton)).perform(click())
|
||||
|
||||
closeSoftKeyboard()
|
||||
|
||||
onView(withId(R.id.publishPost)).perform(click())
|
||||
|
||||
assertTrue(getCurrentActivity()!!::class.java.simpleName == "MainActivity")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clickPublishPost_shouldIncreasePostCount() {
|
||||
cleanLocalStorage(activity)
|
||||
|
||||
onView(withId(R.id.connectedSocialsButton)).perform(click())
|
||||
|
||||
onView(withId(R.id.addSocialRecyclerView))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
TestUtils.actionOnChild(click(), R.id.socialPlatformImage)
|
||||
)
|
||||
)
|
||||
|
||||
pressBack()
|
||||
|
||||
onView(withId(R.id.createPostButton)).perform(click())
|
||||
|
||||
closeSoftKeyboard()
|
||||
|
||||
onView(withId(R.id.availableSocials))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
TestUtils.actionOnChild(click(), R.id.chip)
|
||||
)
|
||||
)
|
||||
|
||||
onView(withId(R.id.publishPost)).perform(click())
|
||||
|
||||
onView(withId(R.id.previousPostsRecyclerView)).check(
|
||||
matches(atPosition(0, hasDescendant(withText("Facebook"))))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.NoMatchingViewException
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.ViewAssertion
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.BoundedMatcher
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
|
||||
import androidx.test.runner.lifecycle.Stage
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.core.AllOf
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.File
|
||||
|
||||
object TestUtils {
|
||||
|
||||
fun cleanLocalStorage(activity: IntentsTestRule<out Activity>) {
|
||||
deleteRecursive(activity.activity.filesDir)
|
||||
}
|
||||
|
||||
private fun deleteRecursive(fileOrDirectory: File) {
|
||||
if (fileOrDirectory.isDirectory())
|
||||
for (child in fileOrDirectory.listFiles())
|
||||
deleteRecursive(child)
|
||||
|
||||
fileOrDirectory.delete()
|
||||
}
|
||||
|
||||
fun actionOnChild(action: ViewAction, childId: Int): ViewAction? {
|
||||
return object : ViewAction {
|
||||
override fun getDescription(): String {
|
||||
return "Action on child"
|
||||
}
|
||||
|
||||
override fun getConstraints(): Matcher<View> {
|
||||
return AllOf.allOf(
|
||||
ViewMatchers.isDisplayed(),
|
||||
ViewMatchers.isAssignableFrom(View::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController?, view: View?) {
|
||||
view?.let {
|
||||
val child = it.findViewById<View>(childId)
|
||||
action.perform(uiController, child)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun atPosition(position: Int, itemMatcher: Matcher<View>): Matcher<View> {
|
||||
checkNotNull(itemMatcher)
|
||||
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("has item at position $position: ")
|
||||
itemMatcher.describeTo(description)
|
||||
}
|
||||
|
||||
override fun matchesSafely(view: RecyclerView): Boolean {
|
||||
val viewHolder = view.findViewHolderForAdapterPosition(position)
|
||||
?: // has no item on such position
|
||||
return false
|
||||
return itemMatcher.matches(viewHolder.itemView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun atPosition(position: Int, id: Int, itemMatcher: Matcher<View>): Matcher<View> {
|
||||
checkNotNull(itemMatcher)
|
||||
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("has item at position $position: ")
|
||||
itemMatcher.describeTo(description)
|
||||
}
|
||||
|
||||
override fun matchesSafely(view: RecyclerView): Boolean {
|
||||
val viewHolder = view.findViewHolderForAdapterPosition(position)
|
||||
?: // has no item on such position
|
||||
return false
|
||||
val view = viewHolder.itemView.findViewById<View>(id)
|
||||
return itemMatcher.matches(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentActivity(): Activity? {
|
||||
var currentActivity: Activity? = null
|
||||
getInstrumentation().runOnMainSync {
|
||||
run {
|
||||
currentActivity =
|
||||
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
|
||||
Stage.RESUMED
|
||||
).elementAtOrNull(0)
|
||||
}
|
||||
}
|
||||
return currentActivity
|
||||
}
|
||||
|
||||
}
|
@ -17,6 +17,7 @@ class FacebookMock : SocialPlatform {
|
||||
|
||||
override fun login(context: Context) {
|
||||
val loginsDir = InternalStorage.getFileOrDir(context, "logins")
|
||||
loginsDir?.mkdir()
|
||||
if (loginsDir != null) {
|
||||
val loginFile = File(loginsDir, "facebook")
|
||||
loginFile.createNewFile()
|
||||
|
15
build.gradle
15
build.gradle
@ -26,3 +26,18 @@ allprojects {
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "28.0.3"
|
||||
androidxLibVersion = "1.0.0"
|
||||
coreVersion = "1.3.0-alpha03"
|
||||
extJUnitVersion = "1.1.2-alpha03"
|
||||
runnerVersion = "1.3.0-alpha03"
|
||||
rulesVersion = "1.3.0-alpha03"
|
||||
espressoVersion = "3.3.0-alpha03"
|
||||
extJUnitVersion = "1.1.2-alpha03"
|
||||
extTruthVersion = "1.3.0-alpha03"
|
||||
robolectricVersion = "4.3.1"
|
||||
}
|
@ -19,3 +19,4 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
android.enableUnitTestBinaryResources=true
|
||||
|
Loading…
Reference in New Issue
Block a user