From 7b18c3eeb774c7b22d2605875c09e28c3252b649 Mon Sep 17 00:00:00 2001 From: Ankush Bose <46471379+bosankus@users.noreply.github.com> Date: Sat, 17 Dec 2022 19:13:34 +0530 Subject: [PATCH] 5115: Fix AdvanceQueryFragmentUnitTests (#5119) * 5115: Fix AdvanceQueryFragmentUnitTests * 5115: Adding further coverage - removed redundant button.post() methods. - increased code coverage --- .../nearby/fragments/AdvanceQueryFragment.kt | 59 ++++--- .../nearby/AdvanceQueryFragmentUnitTests.kt | 150 +++++++++++------- 2 files changed, 136 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/AdvanceQueryFragment.kt b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/AdvanceQueryFragment.kt index b1bf297bd..ed3b741d3 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/AdvanceQueryFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/AdvanceQueryFragment.kt @@ -6,6 +6,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager +import android.widget.Button +import android.widget.EditText import androidx.fragment.app.Fragment import fr.free.nrw.commons.databinding.FragmentAdvanceQueryBinding @@ -13,16 +15,25 @@ class AdvanceQueryFragment : Fragment() { private var _binding: FragmentAdvanceQueryBinding? = null private val binding get() = _binding - lateinit var originalQuery: String + lateinit var callback: Callback + /** + * View Elements + */ + private var etQuery: EditText? = null + private var btnApply: Button? = null + private var btnReset: Button? = null + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = FragmentAdvanceQueryBinding.inflate(inflater, container, false) - originalQuery = arguments?.getString("query")!! + etQuery = binding?.etQuery + btnApply = binding?.btnApply + btnReset = binding?.btnReset setHasOptionsMenu(false) return binding?.root } @@ -30,25 +41,28 @@ class AdvanceQueryFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - with(requireNotNull(binding)) { - etQuery.setText(originalQuery) - btnReset.setOnClickListener { - btnReset.post { - etQuery.setText(originalQuery) - etQuery.clearFocus() - hideKeyBoard() - callback.reset() - } - } + setUi() - btnApply.setOnClickListener { - btnApply.post { - etQuery.clearFocus() - hideKeyBoard() - callback.apply(etQuery.text.toString()) - callback.close() - } - } + setClickListeners() + } + + private fun setUi() { + etQuery?.setText(arguments?.getString("query")!!) + } + + private fun setClickListeners() { + btnReset?.setOnClickListener { + etQuery?.setText(arguments?.getString("query")!!) + etQuery?.clearFocus() + hideKeyBoard() + callback.reset() + } + + btnApply?.setOnClickListener { + etQuery?.clearFocus() + hideKeyBoard() + callback.apply(etQuery?.text.toString()) + callback.close() } } @@ -58,6 +72,11 @@ class AdvanceQueryFragment : Fragment() { inputMethodManager?.hideSoftInputFromWindow(view?.windowToken, 0) } + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } + interface Callback { fun reset() fun apply(query: String) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/nearby/AdvanceQueryFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/nearby/AdvanceQueryFragmentUnitTests.kt index f30060a0d..6d8acd455 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/nearby/AdvanceQueryFragmentUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/nearby/AdvanceQueryFragmentUnitTests.kt @@ -5,26 +5,25 @@ import android.os.Bundle import android.os.Looper import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import android.widget.FrameLayout import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.AppCompatEditText import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentTransaction -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.verify import fr.free.nrw.commons.R import fr.free.nrw.commons.TestAppAdapter import fr.free.nrw.commons.TestCommonsApplication import fr.free.nrw.commons.contributions.MainActivity import fr.free.nrw.commons.nearby.fragments.AdvanceQueryFragment -import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +import org.powermock.reflect.Whitebox import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment @@ -37,20 +36,17 @@ import org.wikipedia.AppAdapter @Config(sdk = [21], application = TestCommonsApplication::class) @LooperMode(LooperMode.Mode.PAUSED) class AdvanceQueryFragmentUnitTests { + + private lateinit var view: View private lateinit var context: Context private lateinit var activity: MainActivity + private lateinit var layoutInflater: LayoutInflater private lateinit var fragment: AdvanceQueryFragment - private lateinit var viewGroup: ViewGroup + private val defaultQuery = "test" @Mock - private lateinit var layoutInflater: LayoutInflater - - @Mock - private lateinit var callback: AdvanceQueryFragment.Callback - - @Mock - private lateinit var view: View + private lateinit var bundle: Bundle @Mock private lateinit var etQuery: AppCompatEditText @@ -62,68 +58,116 @@ class AdvanceQueryFragmentUnitTests { private lateinit var btnApply: AppCompatButton @Mock - private lateinit var bundle: Bundle + private lateinit var callback: AdvanceQueryFragment.Callback @Before fun setUp() { MockitoAnnotations.initMocks(this) - + context = RuntimeEnvironment.getApplication().applicationContext AppAdapter.set(TestAppAdapter()) - context = RuntimeEnvironment.application.applicationContext activity = Robolectric.buildActivity(MainActivity::class.java).create().get() - viewGroup = FrameLayout(context) - - Mockito.`when`(bundle.getString("query")).thenReturn("test") fragment = AdvanceQueryFragment() - fragment.callback = callback fragment.arguments = bundle - + fragment.callback = callback val fragmentManager: FragmentManager = activity.supportFragmentManager val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() fragmentTransaction.add(fragment, null) fragmentTransaction.commit() - Mockito.`when`(layoutInflater.inflate(R.layout.fragment_advance_query, viewGroup, false)) - .thenReturn(view) - Mockito.`when`(view.findViewById(R.id.et_query)).thenReturn(etQuery) - Mockito.`when`(view.findViewById(R.id.btn_apply)).thenReturn(btnApply) - Mockito.`when`(view.findViewById(R.id.btn_reset)).thenReturn(btnReset) - } - - @Test - @Throws(Exception::class) - fun checkFragmentNotNull() { Shadows.shadowOf(Looper.getMainLooper()).idle() - Assert.assertNotNull(fragment) + + layoutInflater = LayoutInflater.from(activity) + view = layoutInflater.inflate(R.layout.fragment_advance_query, null) + + etQuery = view.findViewById(R.id.et_query) + btnApply = view.findViewById(R.id.btn_apply) + btnReset = view.findViewById(R.id.btn_reset) + + Whitebox.setInternalState(fragment, "etQuery", etQuery) + Whitebox.setInternalState(fragment, "btnApply", btnApply) + Whitebox.setInternalState(fragment, "btnReset", btnReset) + + // setting default query + `when`(bundle.getString("query")).thenReturn(defaultQuery) } @Test - fun testOnCreateView() { + fun `check none of the views are null`() { + assertNotNull(activity) + assertNotNull(fragment) + assertNotNull(bundle) + assertNotNull("EditText could not be found", etQuery) + assertNotNull("Button could not be found", btnReset) + assertNotNull("Button could not be found", btnApply) + } + + @Test + fun `when query passed in fragment argument, it is visible in text field`() { Shadows.shadowOf(Looper.getMainLooper()).idle() - fragment.onCreateView(layoutInflater, viewGroup, bundle) - verify(layoutInflater).inflate(R.layout.fragment_advance_query, viewGroup, false) - } - - @Test - fun testOnViewCreated() { - fragment.onCreateView(layoutInflater, viewGroup, bundle) fragment.onViewCreated(view, bundle) - verify(etQuery).setText("test") + assertEquals(defaultQuery, etQuery.text.toString()) + } - Mockito.`when`(btnReset.post(any())).thenAnswer { - it.getArgument(0, Runnable::class.java).run() - } - Mockito.`when`(btnApply.post(any())).thenAnswer { - it.getArgument(0, Runnable::class.java).run() - } - btnReset.performClick() - btnApply.performClick() + @Test + fun `when no query is passed in fragment argument, nothing is visible in text field`() { + `when`(bundle.getString("query")).thenReturn("") + Shadows.shadowOf(Looper.getMainLooper()).idle() + fragment.onViewCreated(view, bundle) + assertEquals("", etQuery.text.toString()) } @Test - fun testHideKeyboard() { - fragment.hideKeyBoard() + fun `when apply button is clicked, callback is notified with new string and screen is closed`() { + // Checking initial query is showing on text view + Shadows.shadowOf(Looper.getMainLooper()).idle() + fragment.onViewCreated(view, bundle) + assertEquals(defaultQuery, etQuery.text.toString()) + + // Setting new query to text view + val newQuery = "$defaultQuery 2" + etQuery.setText(newQuery) + + // Clicking apply button + btnApply.performClick() + + // Verifying if call is notified with changed argument query + verify(callback).apply(newQuery) + verify(callback).close() } -} \ No newline at end of file + + @Test + fun `when reset button is clicked, initial query is visible in text field`() { + // Checking initial query is showing on text view + Shadows.shadowOf(Looper.getMainLooper()).idle() + fragment.onViewCreated(view, bundle) + assertEquals(defaultQuery, etQuery.text.toString()) + + // Setting new query to text view + val newQuery = "$defaultQuery 2" + etQuery.setText(newQuery) + + // Clicking reset button + btnReset.performClick() + + // Verifying if text view is showing initial query and callback is notified + assertEquals(defaultQuery, etQuery.text.toString()) + verify(callback).reset() + } + + @Test + fun `when apply button is clicked with no change, callback is notified and screen is closed`() { + // Checking initial query is showing on text view + Shadows.shadowOf(Looper.getMainLooper()).idle() + fragment.onViewCreated(view, bundle) + assertEquals(defaultQuery, etQuery.text.toString()) + + // Clicking apply button + btnApply.performClick() + + // Verifying if call is notified with initial argument query + verify(callback).apply(defaultQuery) + verify(callback).close() + } +}