diff --git a/app/build.gradle b/app/build.gradle index 14af120a9..ea2887e83 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -84,15 +84,15 @@ dependencies { // Unit testing testImplementation 'junit:junit:4.13.2' - testImplementation 'org.robolectric:robolectric:4.5.1' - testImplementation 'androidx.test:core:1.3.0' + testImplementation 'org.robolectric:robolectric:4.6-alpha-1' + testImplementation 'androidx.test:core:1.4.0' testImplementation "com.squareup.okhttp3:mockwebserver:$OKHTTP_VERSION" testImplementation "com.jraska.livedata:testing-ktx:1.1.2" testImplementation "androidx.arch.core:core-testing:2.1.0" - testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.1" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1" - testImplementation 'com.facebook.soloader:soloader:0.9.0' - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2" + testImplementation "org.junit.jupiter:junit-jupiter-api:5.7.0" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.7.0" + testImplementation 'com.facebook.soloader:soloader:0.10.1' + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.0" // Android testing androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION" @@ -142,6 +142,7 @@ dependencies { def work_version = "2.4.0" // Kotlin + coroutines implementation "androidx.work:work-runtime-ktx:$work_version" + testImplementation "androidx.work:work-testing:$work_version" //Glide implementation 'com.github.bumptech.glide:glide:4.12.0' diff --git a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.java index dce952ca1..78c7d72c0 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsFragment.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; @@ -23,12 +22,10 @@ import com.jakewharton.rxbinding2.widget.RxTextView; import fr.free.nrw.commons.R; import fr.free.nrw.commons.upload.UploadActivity; import fr.free.nrw.commons.upload.UploadBaseFragment; -import fr.free.nrw.commons.upload.UploadModel; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; import fr.free.nrw.commons.utils.DialogUtil; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import javax.inject.Inject; @@ -82,12 +79,9 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra depictsTitle.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1, callback.getTotalNumberOfSteps(), getString(R.string.depicts_step_title))); setDepictsSubTitle(); - tooltip.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - DialogUtil.showAlertDialog(getActivity(), getString(R.string.depicts_step_title), getString(R.string.depicts_tooltip), getString(android.R.string.ok), null, true); - } - }); + tooltip.setOnClickListener(v -> DialogUtil + .showAlertDialog(getActivity(), getString(R.string.depicts_step_title), + getString(R.string.depicts_tooltip), getString(android.R.string.ok), null, true)); presenter.onAttachView(this); initRecyclerView(); addTextChangeListenerToSearchBox(); diff --git a/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt index f578f5769..0c1818f06 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/contributions/MainActivityUnitTests.kt @@ -6,7 +6,7 @@ import android.os.Bundle import android.os.Looper import androidx.fragment.app.Fragment import androidx.work.Configuration -import androidx.work.WorkManager +import androidx.work.testing.WorkManagerTestInitHelper import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.R import fr.free.nrw.commons.TestAppAdapter @@ -105,6 +105,9 @@ class MainActivityUnitTests { MainActivity::class.java.getDeclaredField("contributionsFragment") fieldContributionsFragment.isAccessible = true fieldContributionsFragment.set(activity, contributionsFragment) + + val config: Configuration = Configuration.Builder().build() + WorkManagerTestInitHelper.initializeTestWorkManager(context, config) } @Test @@ -199,8 +202,6 @@ class MainActivityUnitTests { @Throws(Exception::class) fun testToggleLimitedConnectionMode() { Shadows.shadowOf(Looper.getMainLooper()).idle() - val config: Configuration = Configuration.Builder().build() - WorkManager.initialize(context, config) `when`( defaultKvStore.getBoolean( CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED, false diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt index 1e1329082..daa29828e 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadActivityUnitTests.kt @@ -2,6 +2,8 @@ package fr.free.nrw.commons.upload import android.content.Context import android.content.Intent +import androidx.work.Configuration +import androidx.work.testing.WorkManagerTestInitHelper import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.R import fr.free.nrw.commons.TestAppAdapter @@ -62,6 +64,9 @@ class UploadActivityUnitTests { Whitebox.setInternalState(activity, "fragments", mutableListOf(uploadBaseFragment)) Whitebox.setInternalState(activity, "presenter", presenter) Whitebox.setInternalState(activity, "contributionController", contributionController) + + val config: Configuration = Configuration.Builder().build() + WorkManagerTestInitHelper.initializeTestWorkManager(context, config) } @Test @@ -158,7 +163,6 @@ class UploadActivityUnitTests { } @Test - @Ignore() @Throws(Exception::class) fun testMakeUploadRequest() { activity.makeUploadRequest() diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/categories/UploadCategoriesFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/categories/UploadCategoriesFragmentUnitTests.kt index 8620822f3..3370560b6 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/categories/UploadCategoriesFragmentUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/categories/UploadCategoriesFragmentUnitTests.kt @@ -168,7 +168,6 @@ class UploadCategoriesFragmentUnitTests { @Test @Throws(Exception::class) fun testSetCategoriesCaseNonNull() { - Shadows.shadowOf(Looper.getMainLooper()).idle() fragment.setCategories(listOf()) } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/depicts/DepictsFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/depicts/DepictsFragmentUnitTests.kt new file mode 100644 index 000000000..5d2f4b3ed --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/depicts/DepictsFragmentUnitTests.kt @@ -0,0 +1,210 @@ +package fr.free.nrw.commons.upload.depicts + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.TextView +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import fr.free.nrw.commons.R +import fr.free.nrw.commons.TestAppAdapter +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.upload.UploadActivity +import fr.free.nrw.commons.upload.UploadBaseFragment +import io.reactivex.disposables.Disposable +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.powermock.reflect.Whitebox +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import org.wikipedia.AppAdapter +import java.lang.reflect.Method + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +@LooperMode(LooperMode.Mode.PAUSED) +class DepictsFragmentUnitTests { + + private lateinit var fragment: DepictsFragment + private lateinit var fragmentManager: FragmentManager + private lateinit var layoutInflater: LayoutInflater + private lateinit var view: View + private lateinit var context: Context + + @Mock + private lateinit var savedInstanceState: Bundle + + @Mock + private lateinit var textView: TextView + + @Mock + private lateinit var imageView: ImageView + + @Mock + private lateinit var recyclerView: RecyclerView + + @Mock + private lateinit var textInputEditText: TextInputEditText + + @Mock + private lateinit var progressBar: ProgressBar + + @Mock + private lateinit var textInputLayout: TextInputLayout + + @Mock + private lateinit var callback: UploadBaseFragment.Callback + + @Mock + private lateinit var disposable: Disposable + + @Mock + private lateinit var adapter: UploadDepictsAdapter + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + context = RuntimeEnvironment.application.applicationContext + AppAdapter.set(TestAppAdapter()) + + val activity = Robolectric.buildActivity(UploadActivity::class.java).create().get() + fragment = DepictsFragment() + fragmentManager = activity.supportFragmentManager + val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() + fragmentTransaction.add(fragment, null) + fragmentTransaction.commitNowAllowingStateLoss() + + layoutInflater = LayoutInflater.from(activity) + + view = LayoutInflater.from(activity) + .inflate(R.layout.upload_depicts_fragment, null) as View + + Whitebox.setInternalState(fragment, "depictsTitle", textView) + Whitebox.setInternalState(fragment, "callback", callback) + Whitebox.setInternalState(fragment, "tooltip", imageView) + Whitebox.setInternalState(fragment, "depictsSubTitle", textView) + Whitebox.setInternalState(fragment, "depictsRecyclerView", recyclerView) + Whitebox.setInternalState(fragment, "depictsSearch", textInputEditText) + Whitebox.setInternalState(fragment, "depictsSearchContainer", textInputLayout) + Whitebox.setInternalState(fragment, "depictsSearchInProgress", progressBar) + Whitebox.setInternalState(fragment, "subscribe", disposable) + Whitebox.setInternalState(fragment, "adapter", adapter) + } + + @Test + @Throws(Exception::class) + fun checkFragmentNotNull() { + Assert.assertNotNull(fragment) + } + + @Test + @Throws(Exception::class) + fun testOnCreateView() { + fragment.onCreateView(layoutInflater, null, savedInstanceState) + } + + @Test + @Throws(Exception::class) + fun testInit() { + val method: Method = DepictsFragment::class.java.getDeclaredMethod( + "init" + ) + method.isAccessible = true + method.invoke(fragment) + } + + @Test + @Throws(Exception::class) + fun testOnBecameVisible() { + val method: Method = DepictsFragment::class.java.getDeclaredMethod( + "onBecameVisible" + ) + method.isAccessible = true + method.invoke(fragment) + } + + @Test + @Throws(Exception::class) + fun testGoToNextScreen() { + fragment.goToNextScreen() + } + + @Test + @Throws(Exception::class) + fun testGoToPreviousScreen() { + fragment.goToPreviousScreen() + } + + @Test + @Throws(Exception::class) + fun testNoDepictionSelected() { + fragment.noDepictionSelected() + } + + @Test + @Throws(Exception::class) + fun testOnDestroyView() { + fragment.onDestroyView() + } + + @Test + @Throws(Exception::class) + fun testShowProgress() { + fragment.showProgress(true) + } + + @Test + @Throws(Exception::class) + fun testShowErrorCaseTrue() { + fragment.showError(true) + } + + @Test + @Throws(Exception::class) + fun testShowErrorCaseFalse() { + fragment.showError(false) + } + + @Test + @Throws(Exception::class) + fun testSetDepictsList() { + fragment.setDepictsList(listOf()) + } + + @Test + @Throws(Exception::class) + fun testOnNextButtonClicked() { + fragment.onNextButtonClicked() + } + + @Test + @Throws(Exception::class) + fun testOnPreviousButtonClicked() { + fragment.onPreviousButtonClicked() + } + + @Test + @Throws(Exception::class) + fun testSearchForDepictions() { + val method: Method = DepictsFragment::class.java.getDeclaredMethod( + "searchForDepictions", + String::class.java + ) + method.isAccessible = true + method.invoke(fragment, "") + } + +} \ No newline at end of file