diff --git a/app/build.gradle b/app/build.gradle index bf015b3ac..a960a281f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,6 +3,7 @@ plugins { id 'org.jetbrains.kotlin.android' id 'jacoco' id 'kotlin-kapt' + id 'dagger.hilt.android.plugin' } jacoco { @@ -29,7 +30,8 @@ android { versionCode 1 versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" +// testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "ch.sdp.vibester.CustomTestRunner" } buildTypes { @@ -53,6 +55,11 @@ android { unitTests { includeAndroidResources = true } + packagingOptions { + jniLibs { + useLegacyPackaging true + } + } } buildFeatures { viewBinding true @@ -87,7 +94,6 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2' implementation platform('com.google.firebase:firebase-bom:29.1.0') - implementation 'com.google.dagger:dagger:2.38.1' implementation 'com.google.firebase:firebase-analytics-ktx' implementation 'de.hdodenhof:circleimageview:3.1.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' @@ -97,7 +103,16 @@ dependencies { exclude group: 'com.android.support' }) kapt 'com.github.bumptech.glide:compiler:4.13.0' - kapt 'com.google.dagger:dagger-compiler:2.28.3' + + androidTestImplementation 'com.google.dagger:hilt-android-testing:2.38.1' + kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.38.1' + + implementation "com.google.dagger:hilt-android:2.38.1" + kapt "com.google.dagger:hilt-compiler:2.38.1" + + testImplementation "io.mockk:mockk:1.12.3" + androidTestImplementation "io.mockk:mockk-android:1.12.3" + } tasks.withType(Test) { @@ -118,7 +133,6 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'crea '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', - // Exclude Hilt generated classes '**/*Hilt*.*', 'hilt_aggregated_deps/**', '**/*_Factory.class', diff --git a/app/src/androidTest/java/ch/sdp/vibester/CustomTestRunner.kt b/app/src/androidTest/java/ch/sdp/vibester/CustomTestRunner.kt new file mode 100644 index 000000000..6cb2e3601 --- /dev/null +++ b/app/src/androidTest/java/ch/sdp/vibester/CustomTestRunner.kt @@ -0,0 +1,14 @@ +package ch.sdp.vibester + +import android.app.Application +import android.content.Context +import androidx.test.runner.AndroidJUnitRunner +import dagger.hilt.android.testing.HiltTestApplication + +// A custom runner to set up the instrumented application class for tests. +class CustomTestRunner : AndroidJUnitRunner() { + + override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application { + return super.newApplication(cl, HiltTestApplication::class.java.name, context) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/ch/sdp/vibester/activity/AuthenticationActivityTest.kt b/app/src/androidTest/java/ch/sdp/vibester/activity/AuthenticationActivityTest.kt index 7f760ad0d..1d218c49e 100644 --- a/app/src/androidTest/java/ch/sdp/vibester/activity/AuthenticationActivityTest.kt +++ b/app/src/androidTest/java/ch/sdp/vibester/activity/AuthenticationActivityTest.kt @@ -1,10 +1,12 @@ package ch.sdp.vibester.activity +import android.app.Activity import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.core.internal.deps.guava.base.Joiner.on import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.matcher.ViewMatchers.withId @@ -14,12 +16,25 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import ch.sdp.vibester.R import ch.sdp.vibester.auth.FireBaseAuthenticator +import com.google.android.gms.tasks.OnCompleteListener +import com.google.android.gms.tasks.Task +import com.google.firebase.auth.AuthResult +import com.google.firebase.auth.FirebaseUser +import dagger.hilt.android.testing.BindValue +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +//import io.mockk.mockk import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import java.util.concurrent.Executor import kotlin.random.Random @@ -29,11 +44,42 @@ import kotlin.random.Random * See [testing documentation](http://d.android.com/tools/testing). */ @RunWith(AndroidJUnit4::class) +@HiltAndroidTest class AuthenticationActivityTest { private val sleepTime: Long = 5000 + @get:Rule(order = 0) + var hiltRule = HiltAndroidRule(this) + + @get:Rule(order = 1) + val testRule = ActivityScenarioRule( + AuthenticationActivity::class.java + ) + + @BindValue @JvmField + val mockAuthenticator = mockk() + + private fun createMockTask(succesful: Boolean): Task { + val taskResult = mockk>() + + every {taskResult.isSuccessful} returns succesful + every {taskResult.addOnCompleteListener(any(), any>())} answers { + secondArg>().onComplete(taskResult) + taskResult + } + + return taskResult + } + + private fun createMockUser(email: String): FirebaseUser { + val mockUser = mockk() + every { mockUser.email } returns email + return mockUser + } + @Before fun setUp() { + hiltRule.inject() Intents.init() } @@ -48,19 +94,20 @@ class AuthenticationActivityTest { assertEquals("ch.sdp.vibester", appContext.packageName) } - @get:Rule - val testRule = ActivityScenarioRule( - AuthenticationActivity::class.java - ) + @Test fun logInIncorrect() { val username = "johnyyy@test.com" val password = "password" + + val mockTask = createMockTask(false) + every { mockAuthenticator.signIn(username, password) } returns mockTask + onView(withId(R.id.username)).perform(ViewActions.typeText(username), closeSoftKeyboard()) onView(withId(R.id.password)).perform(ViewActions.typeText(password), closeSoftKeyboard()) onView(withId(R.id.logIn)).perform(click()) - Thread.sleep(sleepTime) + Thread.sleep(1000) onView(withId(R.id.email)).check(matches(withText("Authentication error"))) } @@ -68,11 +115,17 @@ class AuthenticationActivityTest { fun createAccountIncorrect() { val username = "john@test.com" val password = "password" + + val mockTask = createMockTask(false) + every { mockAuthenticator.createAccount(username, password) } returns mockTask + onView(withId(R.id.username)).perform(ViewActions.typeText(username), closeSoftKeyboard()) onView(withId(R.id.password)).perform(ViewActions.typeText(password), closeSoftKeyboard()) onView(withId(R.id.createAcc)).perform(click()) - Thread.sleep(sleepTime) + onView(withId(R.id.email)).check(matches(withText("Authentication error"))) + + } @Test @@ -91,9 +144,11 @@ class AuthenticationActivityTest { fun stringValidationWrongEmail() { val username = "john" val password = "password" + onView(withId(R.id.username)).perform(ViewActions.typeText(username), closeSoftKeyboard()) onView(withId(R.id.password)).perform(ViewActions.typeText(password), closeSoftKeyboard()) onView(withId(R.id.createAcc)).perform(click()) + onView(withId(R.id.email)).check(matches(withText("Not an email"))) } @@ -101,47 +156,64 @@ class AuthenticationActivityTest { fun stringValidationShorPassword() { val username = "john@test.com" val password = "12345" + onView(withId(R.id.username)).perform(ViewActions.typeText(username), closeSoftKeyboard()) onView(withId(R.id.password)).perform(ViewActions.typeText(password), closeSoftKeyboard()) onView(withId(R.id.createAcc)).perform(click()) + onView(withId(R.id.email)).check(matches(withText("Password has to be at least 6 symbols"))) } @Test fun derinTest() { val a = FireBaseAuthenticator() + a.googleActivityResult(-1, -1, null) + onView(withId(R.id.email)).check(matches(withText("TextView"))) } @Test fun ardaTest() { val a = FireBaseAuthenticator() + a.googleActivityResult(1000, -1, null) + onView(withId(R.id.email)).check(matches(withText("TextView"))) } @Test fun logInCorrect() { - val username = "lisa@test.com" + val username = "mockUsername@test.com" val password = "password" + + val mockTask = createMockTask(true) + val mockUser = createMockUser(username) + every { mockAuthenticator.signIn(username, password) } returns mockTask + every { mockAuthenticator.getCurrUser()} returns mockUser + onView(withId(R.id.username)).perform(ViewActions.typeText(username), closeSoftKeyboard()) onView(withId(R.id.password)).perform(ViewActions.typeText(password), closeSoftKeyboard()) onView(withId(R.id.logIn)).perform(click()) - Thread.sleep(sleepTime) + Intents.intended(IntentMatchers.hasComponent(ProfileActivity::class.java.name)) Intents.intended(IntentMatchers.hasExtra("email", username)) } @Test fun createAccountCorrect() { - val randomInt = Random.nextInt(0, 10000) + val username = "user@user.com" val password = "password" - val username = randomInt.toString().plus("@gg.com") + + val mockTask = createMockTask(true) + val mockUser = createMockUser(username) + every { mockAuthenticator.createAccount(username, password) } returns mockTask + every { mockAuthenticator.getCurrUser()} returns mockUser + onView(withId(R.id.username)).perform(ViewActions.typeText(username), closeSoftKeyboard()) onView(withId(R.id.password)).perform(ViewActions.typeText(password), closeSoftKeyboard()) onView(withId(R.id.createAcc)).perform(click()) - Thread.sleep(sleepTime) + Intents.intended(IntentMatchers.hasComponent(ProfileActivity::class.java.name)) Intents.intended(IntentMatchers.hasExtra("email", username)) } diff --git a/app/src/androidTest/java/ch/sdp/vibester/activity/ProfileActivityTest.kt b/app/src/androidTest/java/ch/sdp/vibester/activity/ProfileActivityTest.kt index f97423dad..22f002e79 100644 --- a/app/src/androidTest/java/ch/sdp/vibester/activity/ProfileActivityTest.kt +++ b/app/src/androidTest/java/ch/sdp/vibester/activity/ProfileActivityTest.kt @@ -7,26 +7,48 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.intent.Intents -import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.espresso.matcher.ViewMatchers.* //change this import import androidx.test.ext.junit.runners.AndroidJUnit4 import ch.sdp.vibester.R +import ch.sdp.vibester.database.UsersRepo import ch.sdp.vibester.profile.UserProfile +import dagger.hilt.android.testing.BindValue +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import io.mockk.every +import io.mockk.mockk import org.junit.After import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) +@HiltAndroidTest class ProfileActivityTest { private val sleepTime: Long = 4000 + @get:Rule(order = 0) + var hiltRule = HiltAndroidRule(this) + @Before fun setUp() { + hiltRule.inject() Intents.init() } + @BindValue @JvmField + val mockUsersRepo = mockk() + + private fun createMockInvocation(mockProfile: UserProfile) { + every { mockUsersRepo.getUserData(any(), any()) } answers { + secondArg<(UserProfile) -> Unit>().invoke(mockProfile) + } + every { mockUsersRepo.updateField(any(), any(), any()) } answers {} + } + @After fun clean() { Intents.release() @@ -37,13 +59,14 @@ class ProfileActivityTest { val inputProfile = UserProfile("@lisa", "Lalisa Bon","bit.ly/3IUnyAF", "lisa@test.com", 12, 8, 29, 0) val intent = Intent(ApplicationProvider.getApplicationContext(), ProfileActivity::class.java) intent.putExtra("email", inputProfile.email) - intent.putExtra("userProfile", inputProfile) + + createMockInvocation(inputProfile) + val scn: ActivityScenario = ActivityScenario.launch(intent) - Thread.sleep(sleepTime) + onView(withId(R.id.handle)).check(matches(withText(inputProfile.handle))) onView(withId(R.id.username)).check(matches(withText(inputProfile.username))) - //FIXME the data has changed in the database, thus the test is failing -// onView(withId(R.id.correctSongs)).check(matches(withText(inputProfile.correctSongs.toString()))) + onView(withId(R.id.correctSongs)).check(matches(withText(inputProfile.correctSongs.toString()))) onView(withId(R.id.totalGames)).check(matches(withText(inputProfile.totalGames.toString()))) onView(withId(R.id.ranking)).check(matches(withText(inputProfile.ranking.toString()))) } @@ -53,11 +76,15 @@ class ProfileActivityTest { val inputProfile = UserProfile("@lisa", "Lalisa Bon","bit.ly/3IUnyAF", "lisa@test.com", 12, 8, 29, 0) val intent = Intent(ApplicationProvider.getApplicationContext(), ProfileActivity::class.java) intent.putExtra("email", inputProfile.email) + + createMockInvocation(inputProfile) + val scn: ActivityScenario = ActivityScenario.launch(intent) - Thread.sleep(sleepTime) + onView(withId(R.id.profileStatistics)).check(matches(isDisplayed())) onView(withId(R.id.handle)).check(matches(isDisplayed())) onView(withId(R.id.username)).check(matches(isDisplayed())) + //TODO not sure why but this tests fails on CI but passes locally // onView(withId(R.id.avatar)).check(matches(isDisplayed())) } @@ -66,9 +93,12 @@ class ProfileActivityTest { val inputProfile = UserProfile("@lisa", "Lalisa Bon","bit.ly/3IUnyAF", "lisa@test.com", 12, 8, 29, 0) val intent = Intent(ApplicationProvider.getApplicationContext(), ProfileActivity::class.java) intent.putExtra("email", inputProfile.email) + + createMockInvocation(inputProfile) + val scn: ActivityScenario = ActivityScenario.launch(intent) - val newUsername = "Lalisa Bon" + val newUsername = "Lalisa Bon idomesniu" onView(withId(R.id.editUser)).perform(ViewActions.click()) onView(withId(0)).perform( ViewActions.typeText(newUsername), @@ -84,8 +114,11 @@ class ProfileActivityTest { val inputProfile = UserProfile("@lisa", "Lalisa Bon","bit.ly/3IUnyAF", "lisa@test.com", 12, 8, 29, 0) val intent = Intent(ApplicationProvider.getApplicationContext(), ProfileActivity::class.java) intent.putExtra("email", inputProfile.email) + + createMockInvocation(inputProfile) + val scn: ActivityScenario = ActivityScenario.launch(intent) - Thread.sleep(sleepTime) + onView(withId(R.id.editUser)).perform(ViewActions.click()) onView(withText("Cancel")).perform(ViewActions.click()) onView(withId(R.id.username)).check(matches(withText("Lalisa Bon"))) @@ -96,8 +129,11 @@ class ProfileActivityTest { val inputProfile = UserProfile("@lisa", "Lalisa Bon","bit.ly/3IUnyAF", "lisa@test.com", 12, 8, 29, 0) val intent = Intent(ApplicationProvider.getApplicationContext(), ProfileActivity::class.java) intent.putExtra("email", inputProfile.email) + + createMockInvocation(inputProfile) + val scn: ActivityScenario = ActivityScenario.launch(intent) - Thread.sleep(sleepTime) + val newUserHandle = "@lisa" onView(withId(R.id.editHandle)).perform(ViewActions.click()) onView(withId(0)).perform( @@ -114,8 +150,11 @@ class ProfileActivityTest { val inputProfile = UserProfile("@lisa", "Lalisa Bon","bit.ly/3IUnyAF", "lisa@test.com", 12, 8, 29, 0) val intent = Intent(ApplicationProvider.getApplicationContext(), ProfileActivity::class.java) intent.putExtra("email", inputProfile.email) + + createMockInvocation(inputProfile) + val scn: ActivityScenario = ActivityScenario.launch(intent) - Thread.sleep(sleepTime) + onView(withId(R.id.editHandle)).perform(ViewActions.click()) onView(withText("Cancel")).perform(ViewActions.click()) onView(withId(R.id.handle)).check(matches(withText("@lisa"))) diff --git a/app/src/androidTest/java/ch/sdp/vibester/activity/WelcomeActivityTest.kt b/app/src/androidTest/java/ch/sdp/vibester/activity/WelcomeActivityTest.kt index 5d5d14ff8..796e558bb 100644 --- a/app/src/androidTest/java/ch/sdp/vibester/activity/WelcomeActivityTest.kt +++ b/app/src/androidTest/java/ch/sdp/vibester/activity/WelcomeActivityTest.kt @@ -9,16 +9,25 @@ import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import ch.sdp.vibester.R +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +@HiltAndroidTest @RunWith(AndroidJUnit4::class) class WelcomeActivityTest { - @get: Rule - val activityRule = ActivityScenarioRule(WelcomeActivity::class.java) + @get:Rule(order = 0) + var hiltRule = HiltAndroidRule(this) + + + @get:Rule(order = 1) + val testRule = ActivityScenarioRule( + WelcomeActivity::class.java + ) @Before fun setUp() { diff --git a/app/src/androidTest/java/ch/sdp/vibester/profile/ProfileDataProviderTest.kt b/app/src/androidTest/java/ch/sdp/vibester/profile/ProfileDataProviderTest.kt deleted file mode 100644 index 1f1ac6d44..000000000 --- a/app/src/androidTest/java/ch/sdp/vibester/profile/ProfileDataProviderTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package ch.sdp.vibester.profile - -//import ch.sdp.vibester.profile.ProfileDataProvider - - -class ProfileDataProviderTest { - -// @Test -// fun checkGetUserData(){ -// val userID = 0 -// val users: List = listOf( -// UserProfile("user0", "username0","https://bit.ly/3tO0k8W", 5, 8, 34), -// UserProfile("user1", "username1", "https://bit.ly/3sZhbXm", 5, 8, 34) -// ) -// val scoreboard: List = listOf(1,2,3,4,5,6) -// val dataProvider = ProfileDataProvider(userID.toString(), users, scoreboard) -// val finalUser = dataProvider.getUserProfileData() -// -// // To change on recursive equality of objects -// Assert.assertEquals(finalUser.handle, users[userID].handle) -// Assert.assertEquals(finalUser.username, users[userID].username) -// Assert.assertEquals(finalUser.image, users[userID].image) -// Assert.assertEquals(finalUser.bestScore, users[userID].bestScore) -// Assert.assertEquals(finalUser.totalGames, users[userID].totalGames) -// Assert.assertEquals(finalUser.correctSongs, users[userID].correctSongs) -// Assert.assertEquals(finalUser.ranking, scoreboard[userID]) -// } - - -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2a466cc87..b984e5dad 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,12 +9,14 @@ (R.id.createAcc) val btLogIn = findViewById