5115: Fix AdvanceQueryFragmentUnitTests (#5119)

* 5115: Fix AdvanceQueryFragmentUnitTests

* 5115: Adding further coverage
- removed redundant button.post() methods.
- increased code coverage
This commit is contained in:
Ankush Bose 2022-12-17 19:13:34 +05:30 committed by GitHub
parent 77bb789f9e
commit 7b18c3eeb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 136 additions and 73 deletions

View file

@ -6,6 +6,8 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import fr.free.nrw.commons.databinding.FragmentAdvanceQueryBinding import fr.free.nrw.commons.databinding.FragmentAdvanceQueryBinding
@ -13,16 +15,25 @@ class AdvanceQueryFragment : Fragment() {
private var _binding: FragmentAdvanceQueryBinding? = null private var _binding: FragmentAdvanceQueryBinding? = null
private val binding get() = _binding private val binding get() = _binding
lateinit var originalQuery: String
lateinit var callback: Callback lateinit var callback: Callback
/**
* View Elements
*/
private var etQuery: EditText? = null
private var btnApply: Button? = null
private var btnReset: Button? = null
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
_binding = FragmentAdvanceQueryBinding.inflate(inflater, container, false) _binding = FragmentAdvanceQueryBinding.inflate(inflater, container, false)
originalQuery = arguments?.getString("query")!! etQuery = binding?.etQuery
btnApply = binding?.btnApply
btnReset = binding?.btnReset
setHasOptionsMenu(false) setHasOptionsMenu(false)
return binding?.root return binding?.root
} }
@ -30,25 +41,28 @@ class AdvanceQueryFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
with(requireNotNull(binding)) { setUi()
etQuery.setText(originalQuery)
btnReset.setOnClickListener {
btnReset.post {
etQuery.setText(originalQuery)
etQuery.clearFocus()
hideKeyBoard()
callback.reset()
}
}
btnApply.setOnClickListener { setClickListeners()
btnApply.post { }
etQuery.clearFocus()
hideKeyBoard() private fun setUi() {
callback.apply(etQuery.text.toString()) etQuery?.setText(arguments?.getString("query")!!)
callback.close() }
}
} 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) inputMethodManager?.hideSoftInputFromWindow(view?.windowToken, 0)
} }
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
interface Callback { interface Callback {
fun reset() fun reset()
fun apply(query: String) fun apply(query: String)

View file

@ -5,26 +5,25 @@ import android.os.Bundle
import android.os.Looper import android.os.Looper
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.AppCompatButton
import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.AppCompatEditText
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction 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.R
import fr.free.nrw.commons.TestAppAdapter import fr.free.nrw.commons.TestAppAdapter
import fr.free.nrw.commons.TestCommonsApplication import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.contributions.MainActivity import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.nearby.fragments.AdvanceQueryFragment 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.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.Robolectric import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment import org.robolectric.RuntimeEnvironment
@ -37,20 +36,17 @@ import org.wikipedia.AppAdapter
@Config(sdk = [21], application = TestCommonsApplication::class) @Config(sdk = [21], application = TestCommonsApplication::class)
@LooperMode(LooperMode.Mode.PAUSED) @LooperMode(LooperMode.Mode.PAUSED)
class AdvanceQueryFragmentUnitTests { class AdvanceQueryFragmentUnitTests {
private lateinit var view: View
private lateinit var context: Context private lateinit var context: Context
private lateinit var activity: MainActivity private lateinit var activity: MainActivity
private lateinit var layoutInflater: LayoutInflater
private lateinit var fragment: AdvanceQueryFragment private lateinit var fragment: AdvanceQueryFragment
private lateinit var viewGroup: ViewGroup private val defaultQuery = "test"
@Mock @Mock
private lateinit var layoutInflater: LayoutInflater private lateinit var bundle: Bundle
@Mock
private lateinit var callback: AdvanceQueryFragment.Callback
@Mock
private lateinit var view: View
@Mock @Mock
private lateinit var etQuery: AppCompatEditText private lateinit var etQuery: AppCompatEditText
@ -62,68 +58,116 @@ class AdvanceQueryFragmentUnitTests {
private lateinit var btnApply: AppCompatButton private lateinit var btnApply: AppCompatButton
@Mock @Mock
private lateinit var bundle: Bundle private lateinit var callback: AdvanceQueryFragment.Callback
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
context = RuntimeEnvironment.getApplication().applicationContext
AppAdapter.set(TestAppAdapter()) AppAdapter.set(TestAppAdapter())
context = RuntimeEnvironment.application.applicationContext
activity = Robolectric.buildActivity(MainActivity::class.java).create().get() activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
viewGroup = FrameLayout(context)
Mockito.`when`(bundle.getString("query")).thenReturn("test")
fragment = AdvanceQueryFragment() fragment = AdvanceQueryFragment()
fragment.callback = callback
fragment.arguments = bundle fragment.arguments = bundle
fragment.callback = callback
val fragmentManager: FragmentManager = activity.supportFragmentManager val fragmentManager: FragmentManager = activity.supportFragmentManager
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(fragment, null) fragmentTransaction.add(fragment, null)
fragmentTransaction.commit() fragmentTransaction.commit()
Mockito.`when`(layoutInflater.inflate(R.layout.fragment_advance_query, viewGroup, false))
.thenReturn(view)
Mockito.`when`(view.findViewById<AppCompatEditText>(R.id.et_query)).thenReturn(etQuery)
Mockito.`when`(view.findViewById<AppCompatButton>(R.id.btn_apply)).thenReturn(btnApply)
Mockito.`when`(view.findViewById<AppCompatButton>(R.id.btn_reset)).thenReturn(btnReset)
}
@Test
@Throws(Exception::class)
fun checkFragmentNotNull() {
Shadows.shadowOf(Looper.getMainLooper()).idle() 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 @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() 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) 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 { @Test
it.getArgument(0, Runnable::class.java).run() fun `when no query is passed in fragment argument, nothing is visible in text field`() {
} `when`(bundle.getString("query")).thenReturn("")
btnReset.performClick() Shadows.shadowOf(Looper.getMainLooper()).idle()
btnApply.performClick() fragment.onViewCreated(view, bundle)
assertEquals("", etQuery.text.toString())
} }
@Test @Test
fun testHideKeyboard() { fun `when apply button is clicked, callback is notified with new string and screen is closed`() {
fragment.hideKeyBoard() // 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()
} }
}
@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()
}
}