From b0813b61107802bac290a81e01c0c442b3569fda Mon Sep 17 00:00:00 2001 From: ksergeevit <64887317+ksergeevit@users.noreply.github.com> Date: Tue, 9 Jun 2020 10:20:35 +0300 Subject: [PATCH] EN tests (#284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakob Möller <jakob.moeller@sap.com> --- Corona-Warn-App/build.gradle | 3 +- .../java/de/rki/coronawarnapp/TestFragment.kt | 20 +++ ...xposureNotificationPermissionHelperTest.kt | 158 ++++++++++++++++++ .../ExposureStateUpdateReceiverTest.kt | 56 +++++++ 4 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt create mode 100644 Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle index 3ad809646..179b21c57 100644 --- a/Corona-Warn-App/build.gradle +++ b/Corona-Warn-App/build.gradle @@ -181,7 +181,8 @@ dependencies { androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test.ext:truth:1.2.0' androidTestImplementation 'androidx.test.ext:junit:1.1.1' - + androidTestImplementation "io.mockk:mockk-android:1.10.0" + debugImplementation 'androidx.fragment:fragment-testing:1.2.4' // Play Services implementation 'com.google.android.play:core:1.7.3' diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt new file mode 100644 index 000000000..45170cdb4 --- /dev/null +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment + +/** + * Test fragment with test view, [TextView] required for view lifecycle owner. + * + * @see [Fragment.getViewLifecycleOwner] + */ +class TestFragment : Fragment() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return TextView(this.context) + } +} diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt new file mode 100644 index 000000000..ebcab98c7 --- /dev/null +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt @@ -0,0 +1,158 @@ +package de.rki.coronawarnapp.nearby + +import androidx.fragment.app.Fragment +import androidx.fragment.app.testing.FragmentScenario +import androidx.fragment.app.testing.launchFragmentInContainer +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Status +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.CoronaWarnApplication +import de.rki.coronawarnapp.TestFragment +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.unmockkAll +import org.hamcrest.CoreMatchers.`is` +import org.hamcrest.MatcherAssert.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** + * InternalExposureNotificationPermissionHelper test. + */ +@RunWith(AndroidJUnit4::class) +class InternalExposureNotificationPermissionHelperTest { + private lateinit var scenario: FragmentScenario<TestFragment> + private var fail = false + private var startSuccess = false + private var sharingSuccess = false + private val callback = object : InternalExposureNotificationPermissionHelper.Callback { + override fun onFailure(exception: Exception?) { + fail = true + } + override fun onStartPermissionGranted() { + startSuccess = true + } + override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) { + sharingSuccess = true + } + } + + /** + * Launch test fragment, required for view lifecycle owner. + * + * @see [InternalExposureNotificationPermissionHelper] + * @see [Fragment.getViewLifecycleOwner] + */ + @Before + fun setUp() { + fail = false + startSuccess = false + sharingSuccess = false + mockkObject(InternalExposureNotificationClient) + scenario = launchFragmentInContainer<TestFragment>() + } + + /** + * Test tracing permission request assuming EN Client is enabled. + */ + @Test + fun testRequestPermissionToStartTracingENIsEnabled() { + coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns true + scenario.onFragment { + val helper = InternalExposureNotificationPermissionHelper(it, callback) + helper.requestPermissionToStartTracing() + } + assertThat(fail, `is`(false)) + assertThat(startSuccess, `is`(true)) + } + + /** + * Test tracing permission request assuming EN Client is disabled. + */ + @Test + fun testRequestPermissionToStartTracingENIsNotEnabled() { + coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns false + // not every device/emulator has access to exposure notifications Google API: + coEvery { InternalExposureNotificationClient.asyncStart() } returns mockk() + + scenario.onFragment { + val helper = InternalExposureNotificationPermissionHelper(it, callback) + helper.requestPermissionToStartTracing() + } + assertThat(fail, `is`(false)) + assertThat(startSuccess, `is`(true)) + } + + /** + * Test tracing permission request exception handling. + */ + @Test + fun testRequestPermissionToStartTracingExceptionHandling() { + coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns false + + // not every device/emulator has access to exposure notifications Google API: + coEvery { InternalExposureNotificationClient.asyncStart() } throws mockApiException(Status.RESULT_CANCELED) + + scenario.onFragment { + val helper = InternalExposureNotificationPermissionHelper(it, callback) + helper.requestPermissionToStartTracing() + } + assertThat(fail, `is`(true)) + assertThat(startSuccess, `is`(false)) + } + + /** + * Test keys sharing permission request. + */ + @Test + fun testRequestPermissionToShareKeys() { + // not every device/emulator has access to exposure notifications Google API: + coEvery { InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() } returns mockk() + + scenario.onFragment { + val helper = InternalExposureNotificationPermissionHelper(it, callback) + helper.requestPermissionToShareKeys() + } + assertThat(fail, `is`(false)) + assertThat(sharingSuccess, `is`(true)) + } + + /** + * Test keys sharing permission request exception handling. + */ + @Test + fun testRequestPermissionToShareKeysException() { + // not every device/emulator has access to exposure notifications Google API: + coEvery { + InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() + } throws mockApiException(Status.RESULT_CANCELED) + + scenario.onFragment { + val helper = InternalExposureNotificationPermissionHelper(it, callback) + helper.requestPermissionToShareKeys() + } + assertThat(fail, `is`(true)) + assertThat(sharingSuccess, `is`(false)) + } + + private fun mockApiException(status: Status): ApiException { + mockkObject(LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext())) + val exception = ApiException(status) + // don't need a dialog for exception + every { + LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext()).sendBroadcast(any()) + } returns true + return exception + } + + @After + fun cleanUp() { + unmockkAll() + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt new file mode 100644 index 000000000..19ac4f2c8 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt @@ -0,0 +1,56 @@ +package de.rki.coronawarnapp.receiver + +import android.content.Context +import android.content.Intent +import androidx.work.WorkManager +import androidx.work.WorkRequest +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.verify +import org.junit.After +import org.junit.Before +import org.junit.Test + +/** + * ExposureStateUpdateReceiver test. + */ +class ExposureStateUpdateReceiverTest { + @MockK + private lateinit var context: Context + @MockK + private lateinit var intent: Intent + + @Before + fun setUp() { + MockKAnnotations.init(this) + mockkStatic(WorkManager::class) + every { intent.action } returns ExposureNotificationClient.ACTION_EXPOSURE_STATE_UPDATED + every { intent.getStringExtra(ExposureNotificationClient.EXTRA_TOKEN) } returns "token" + } + + /** + * Test ExposureStateUpdateReceiver. + */ + @Test + fun testExposureStateUpdateReceiver() { + val wm = mockk<WorkManager>() + every { WorkManager.getInstance(context) } returns wm + every { wm.enqueue(any<WorkRequest>()) } answers { mockk() } + + ExposureStateUpdateReceiver().onReceive(context, intent) + + verify { + wm.enqueue(any<WorkRequest>()) + } + } + + @After + fun cleanUp() { + unmockkAll() + } +} -- GitLab