Android测试片段和登录操作

huangapple go评论103阅读模式
英文:

Android testing fragments and login action

问题

  1. Your test is failing because it's not able to find a view with the ID 2131362204 which corresponds to R.id.email. This means there might be an issue with the setup or the view hierarchy in your test environment.

  2. To test your login logic with Firebase Realtime Database, you can use Firebase's testing tools. Firebase provides a testing emulator suite that allows you to write unit tests and integration tests for Firebase features. You can find more information in the Firebase documentation on how to set up and use these emulators for testing.

  3. For simple unit tests that don't involve UI interactions, you can create separate test classes and functions for your business logic. These tests can be written using standard testing frameworks like JUnit or Kotlin's built-in testing tools. You can write tests to validate different scenarios of your login logic, including cases where the user input is blank or invalid. This will help ensure the correctness of your code.

英文:

Hi guys i'm trying to test my android app.It is an app used for the restaurant industry similar to just eat for example.
I've done some testing on generic navigation and now I want to test the login action and see if the fragments are loaded.

This is my test class

  1. @Test
  2. fun test_Login_to_FragmentRistoranti(){
  3. //Setup activity scenario
  4. val activityScenario= ActivityScenario.launch(IntroActivity::class.java)
  5. //Perform click action per andare a LogIn
  6. Espresso.onView(ViewMatchers.withId(R.id.ConstraintLogin))
  7. .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
  8. Espresso.onView(ViewMatchers.withId(R.id.ConstraintLogin)).perform(ViewActions.click())
  9. //login action user livello 1
  10. val email:String="useruser@gmail.com"
  11. val pwd:String="useruser"
  12. Espresso.onView(ViewMatchers.withId(R.id.email)).perform(ViewActions.typeText(email))
  13. closeSoftKeyboard()
  14. Espresso.onView(ViewMatchers.withId(R.id.password)).perform(ViewActions.typeText(pwd))
  15. closeSoftKeyboard()
  16. Espresso.onView(ViewMatchers.withId(R.id.ConstraintLogin)).perform(ViewActions.click())
  17. //Controllo dopo il login che si veda fragmentRistoranti
  18. Espresso.onView(ViewMatchers.withId(R.id.swipe_refresh_ristoranti))
  19. .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
  20. //logout e controllo che si veda login
  21. Espresso.onView(ViewMatchers.withId(R.id.ic_logoutU)).perform(ViewActions.click())
  22. //Perform click action per andare a LogIn
  23. Espresso.onView(ViewMatchers.withId(R.id.ConstraintLogin))
  24. .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
  25. }

And this is my FragmentLogin class

  1. package com.example.progettoprogrammazione.intro
  2. import android.content.Intent
  3. import android.os.Bundle
  4. import android.view.LayoutInflater
  5. import android.view.View
  6. import android.view.ViewGroup
  7. import android.widget.Toast
  8. import androidx.fragment.app.Fragment
  9. import androidx.navigation.findNavController
  10. import com.example.progettoprogrammazione.R
  11. import com.example.progettoprogrammazione.activity.EmployeeActivity
  12. import com.example.progettoprogrammazione.activity.RestaurateurActivity
  13. import com.example.progettoprogrammazione.activity.UserActivity
  14. import com.example.progettoprogrammazione.databinding.Fragment0LoginBinding
  15. import com.example.progettoprogrammazione.firebase.FireBaseCallbackRestaurant
  16. import com.example.progettoprogrammazione.firebase.FireBaseCallbackCart
  17. import com.example.progettoprogrammazione.firebase.FireBaseCallbackUser
  18. import com.example.progettoprogrammazione.utils.*
  19. import com.google.firebase.auth.FirebaseAuth
  20. import com.google.firebase.database.FirebaseDatabase
  21. // Made by Alessandro Pieragostini, Matteo Sonaglioni & Stefano Marcucci
  22. /* Chi utilizza questo fragment può accedere all'interno dell'applicazione, a seconda del livello
  23. utente, oppure navigare alla pagina Registrati */
  24. class FragmentLogin : Fragment(), UserUtils, DipendenteUtils, RestaurantUtils, ProductUtils,
  25. CartUtils {
  26. private lateinit var binding: Fragment0LoginBinding
  27. override var firebaseAuth: FirebaseAuth = FirebaseAuth.getInstance()
  28. override var firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()
  29. private var userlvl: String? = null
  30. private lateinit var useremail: String
  31. fun login(email:String, password:String){
  32. if (email.isNotEmpty() && password.isNotEmpty()) {
  33. firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener {
  34. if (it.isSuccessful) {
  35. //LOGIN
  36. getUserData(object : FireBaseCallbackUser {
  37. override fun onResponse(responseU: ResponseUser) {
  38. userlvl = responseU.user!!.Livello
  39. Toast.makeText(
  40. context,
  41. "Login effettuato con successo!",
  42. Toast.LENGTH_LONG
  43. )
  44. .show()
  45. getQRData(
  46. FirebaseAuth.getInstance().uid,
  47. object : FireBaseCallbackCart {
  48. override fun onResponse(responseC: ResponseCart) {
  49. getRestaurantData(object : FireBaseCallbackRestaurant {
  50. override fun onResponse(responseR: ResponseRistorante) {
  51. when (userlvl) {
  52. "1" -> {
  53. val intent =
  54. Intent(
  55. context,
  56. UserActivity::class.java
  57. ).apply {
  58. putExtra("user", responseU.user)
  59. putParcelableArrayListExtra(
  60. "ristoranti",
  61. responseR.ristoranti
  62. )
  63. putExtra(
  64. "cart",
  65. responseC.cart
  66. )
  67. }
  68. startActivity(intent)
  69. activity?.finish()
  70. }
  71. "2" -> {
  72. val intent =
  73. Intent(
  74. context,
  75. EmployeeActivity::class.java
  76. ).apply {
  77. putExtra("user", responseU.user)
  78. putParcelableArrayListExtra(
  79. "ristoranti",
  80. responseR.ristoranti
  81. )
  82. putExtra(
  83. "cart",
  84. responseC.cart
  85. )
  86. }
  87. startActivity(intent)
  88. activity?.finish()
  89. }
  90. "3" -> {
  91. val intent =
  92. Intent(
  93. context,
  94. RestaurateurActivity::class.java
  95. ).apply {
  96. putExtra("user", responseU.user)
  97. putParcelableArrayListExtra(
  98. "ristoranti",
  99. responseR.ristoranti
  100. )
  101. putExtra(
  102. "cart",
  103. responseC.cart
  104. )
  105. }
  106. startActivity(intent)
  107. activity?.finish()
  108. }
  109. else -> {
  110. Toast.makeText(
  111. context,
  112. "Errore durante il caricamento.",
  113. Toast.LENGTH_LONG
  114. ).show()
  115. }
  116. }
  117. }
  118. }, context)
  119. }
  120. },
  121. context
  122. )
  123. }
  124. }, context)
  125. } else Toast.makeText(
  126. context,
  127. "Email e password non corrispondono!",
  128. Toast.LENGTH_LONG
  129. ).show()
  130. }
  131. } else {
  132. Toast.makeText(context, "Nessun campo può essere vuoto!", Toast.LENGTH_LONG)
  133. .show()
  134. }
  135. }
  136. override fun onCreateView(
  137. inflater: LayoutInflater,
  138. container: ViewGroup?,
  139. savedInstanceState: Bundle?
  140. ): View {
  141. binding = Fragment0LoginBinding.inflate(layoutInflater)
  142. return binding.root
  143. }
  144. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  145. super.onViewCreated(view, savedInstanceState)
  146. firebaseAuth = FirebaseAuth.getInstance()
  147. // Questa funzione permette di effettuare il login quando i campi di email e password corrispondono
  148. // ad un account già creato e, a seconda del livello, si effettuerà la navigazione in una delle Activity
  149. binding.ConstraintLogin.setOnClickListener {
  150. login( binding.email.text.toString(), binding.password.text.toString())
  151. }
  152. // Cliccando in questo bottone, verrà mandata una mail di recupero password
  153. binding.recuperapassword.setOnClickListener {
  154. useremail = binding.email.text.toString()
  155. if (useremail.isNotEmpty()) {
  156. recoverUserPassword(context, useremail)
  157. } else Toast.makeText(context, "Inserisci un'email.", Toast.LENGTH_SHORT).show()
  158. }
  159. // Cliccando sul bottone, la navigazione porterà alla pagina "Registrati"
  160. binding.noaccount.setOnClickListener {
  161. view.findNavController().navigate(R.id.LoginToRegister)
  162. }
  163. }

}

The error of the test class is reported below

  1. androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching:
  2. view.getId() is <2131362204/com.example.progettoprogrammazione:id/email>
  3. View Hierarchy:
  4. +>DecorView{id=-1, visibility=VISIBLE, width=1080, height=2280, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302fe
  5. fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
  6. pfl=NO_MOVE_ANIMATION FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
  7. bhv=DEFAULT
  8. fitSides=}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3}
  9. |
  10. +->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=2214, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
  11. |
  12. +-->ViewStub{id=16908746, res-name=action_mode_bar_stub, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
  13. |
  14. +-->FrameLayout{id=-1, visibility=VISIBLE, width=1080, height=2148, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=66.0, child-count=1}
  15. |
  16. +--->ActionBarOverlayLayout{id=2131362158, res-name=decor_content_parent, visibility=VISIBLE, width=1080, height=2148, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
  17. |
  18. +---->ContentFrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=1080, height=1994, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.ActionBarOverlayLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=154.0, child-count=1}
  19. |
  20. +----->ConstraintLayout{id=2131362320, res-name=intro_activity, visibility=VISIBLE, width=1080, height=1994, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
  21. |
  22. +------>FragmentContainerView{id=2131362417, res-name=nav_host, visibility=VISIBLE, width=1080, height=1994, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
  23. |
  24. +------->FragmentContainerView{id=2131362417, res-name=nav_host, visibility=VISIBLE, width=1080, height=1994, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
  25. |
  26. +-------->ConstraintLayout{id=-1, visibility=VISIBLE, width=1080, height=1994, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
  27. |
  28. +--------->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=1994, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=4}
  29. |
  30. +---------->AppCompatImageView{id=2131362307, res-name=image_intro, visibility=VISIBLE, width=871, height=871, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=104.0, y=55.0}
  31. |
  32. +---------->MaterialTextView{id=2131361945, res-name=benvenuto_text, visibility=VISIBLE, width=720, height=88, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=180.0, y=926.0, text=Benvenuto su Cookade!, input-type=0, ime-target=false, has-links=false}
  33. |
  34. +---------->LinearLayout{id=-1, visibility=VISIBLE, width=970, height=279, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=55.0, y=1152.0, child-count=1}
  35. |
  36. +----------->LinearLayout{id=-1, visibility=VISIBLE, width=936, height=279, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=17.0, y=0.0, child-count=2}
  37. |
  38. +------------>ConstraintLayout{id=2131361801, res-name=ConstraintLogin, visibility=VISIBLE, width=550, height=138, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=193.0, y=55.0, child-count=1}
  39. |
  40. +------------->MaterialTextView{id=2131362346, res-name=login, visibility=VISIBLE, width=163, height=71, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=194.0, y=34.0, text=LOGIN, input-type=0, ime-target=false, has-links=false}
  41. |
  42. +------------>MaterialTextView{id=-1, visibility=VISIBLE, width=826, height=3, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=55.0, y=221.0, text=, input-type=0, ime-target=false, has-links=false}
  43. |
  44. +---------->LinearLayout{id=-1, visibility=VISIBLE, width=970, height=127, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=55.0, y=1431.0, child-count=1}
  45. |
  46. +----------->MaterialTextView{id=2131362547, res-name=registrati, visibility=VISIBLE, width=914, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=28.0, y=28.0, text=Non sei registrato? Clicca qui!, input-type=0, ime-target=false, has-links=false}
  47. |
  48. +---->ActionBarContainer{id=2131361899, res-name=action_bar_container, visibility=VISIBLE, width=1080, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.ActionBarOverlayLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
  49. |
  50. +----->Toolbar{id=2131361897, res-name=action_bar, visibility=VISIBLE, width=1080, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
  51. |
  52. +------>AppCompatTextView{id=-1, visibility=VISIBLE, width=269, height=71, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=44.0, y=41.0, text=COOKADE, input-type=0, ime-target=false, has-links=false}
  53. |
  54. +------>ActionMenuView{id=-1, visibility=VISIBLE, width=0, height=154, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.appcompat.widget.Toolbar$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=1080.0, y=0.0, child-count=0}
  55. |
  56. +----->ActionBarContextView{id=2131361905, res-name=action_context_bar, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=0}
  57. |
  58. +->View{id=16908336, res-name=navigationBarBackground, visibility=VISIBLE, width=1080, height=66, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=2214.0}
  59. |
  60. +->View{id=16908335, res-name=statusBarBackground, visibility=VISIBLE, width=1080, height=66, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@YYYYYY, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
  61. at androidx.test.espresso.NoMatchingViewException$Builder.build(NoMatchingViewException.java:5)
  62. at androidx.test.espresso.base.DefaultFailureHandler.lambda$getNoMatchingViewExceptionTruncater$0(DefaultFailureHandler.java:5)
  63. at androidx.test.espresso.base.DefaultFailureHandler$$ExternalSyntheticLambda1.truncateExceptionMessage(Unknown Source:2)
  64. at androidx.test.espresso.base.ViewHierarchyExceptionHandler.handleSafely(ViewHierarchyExceptionHandler.java:5)
  65. at androidx.test.espresso.base.ViewHierarchyExceptionHandler.handleSafely(ViewHierarchyExceptionHandler.java:1)
  66. at androidx.test.espresso.base.DefaultFailureHandler$TypedFailureHandler.handle(DefaultFailureHandler.java:4)
  67. at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:5)
  68. at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:8)
  69. at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:11)
  70. at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:8)
  71. at com.example.progettoprogrammazione.UserNavigationTesting.test_Login_to_FragmentRistoranti(UserNavigationTesting.kt:46)

Now I want to ask a couple of questions:
1)Why my test returns failed
2)How can i test my login logic in a better way. We use in our project firebase realtimedb and i do not know how to implement testing (like i want to test if i let the user text view blank , ecc)
3)Where i can do some simple testing and not UI tests

答案1

得分: 1

你的测试失败是因为在点击 R.id.ConstraintLogin 后,预期的视图未显示在屏幕上。这可能是由于多种原因,例如片段/活动加载时间比测试时间长,或者视图不包含点击监听器。您需要分享更多的代码,以便我能够准确定位问题。如果是由于时间问题,我还建议查看空闲资源。

如果您想更好地测试自己的逻辑,那么您需要将您自己的逻辑代码部分提取到单独的函数中进行单元测试。针对数据库进行测试并不是一个好主意,而是应该模拟数据并使数据访问层用于测试目的。简单的测试是通过单元测试完成的,您可以在这里测试数据类和函数,但请注意,如果不使用框架(如 mockjay 或 mockito),您将无法获得 Android 上下文。

英文:

Your test is failing because after the click action on R.id.ConstraintLogin, the expected view is not showing on the screen. This could be due to a number of reasons, such as due to the fragment/activity loading is taking longer than the test or that the view does not contain the click listener. You would have to share a little more code for me to be able to pinpoint the problem. I would also suggest looking into Idling resources if its due to a timing issue.

If you want to test your own logic better, then you will need to extract the code parts that are your own logic into separate functions for unit testing. Testing against a DB is not a good idea, instead you should mock the data and make the data access layer abstract for testing purposes.

Simple testing is done with unit tests, here you can test data classes and functions, but beware, you have no android context without using a framework such as mockjay or mockito.

huangapple
  • 本文由 发表于 2023年6月13日 16:04:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76462855.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定