Android fragments 在UI测试中显示片段内的对话框(对话框片段)

Android fragments 在UI测试中显示片段内的对话框(对话框片段),android-fragments,testing,android-espresso,android-dialogfragment,android-fragmentscenario,Android Fragments,Testing,Android Espresso,Android Dialogfragment,Android Fragmentscenario,我正在为一个片段编写UI测试用例。我使用launchFragmentInContainer独立于活动启动片段 场景是,点击一个按钮,应该会显示一个对话框片段,但当我这样做时,屏幕上什么也不会显示 这是我的主要片段 package com.cbre.host.onboarding.locationaccess import android.Manifest import android.content.pm.PackageManager import android.os.Bundle

我正在为一个片段编写UI测试用例。我使用launchFragmentInContainer独立于活动启动片段

场景是,点击一个按钮,应该会显示一个对话框片段,但当我这样做时,屏幕上什么也不会显示

这是我的主要片段

    package com.cbre.host.onboarding.locationaccess

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.navigation.fragment.findNavController
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.cbre.host.common.AppNavigator
import com.cbre.host.common.BaseFragment
import com.cbre.host.common.utils.Constants
import com.cbre.host.core.permission.PermissionProvider
import com.cbre.host.onboarding.R
import com.cbre.host.onboarding.databinding.LocationAccessFragmentBinding
import kotlinx.android.synthetic.main.location_access_fragment.*
import org.koin.android.ext.android.inject

class LocationAccessFragment : BaseFragment() {

    private lateinit var binding: LocationAccessFragmentBinding
    private val _viewModel: LocationAccessViewModel by fragmentViewModel()
    private val _permissionProvider: PermissionProvider by inject()
    private val _appNavigator: AppNavigator by inject()


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = LocationAccessFragmentBinding.inflate(inflater, container, false)
        binding.lifecycleOwner = viewLifecycleOwner
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        requireActivity().onBackPressedDispatcher.addCallback(
            viewLifecycleOwner,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    // DO NOTHING
                }
            })

        may_be_later.setOnClickListener { findNavController().navigate(R.id.next_action_a) }
        access_location.setOnClickListener { handleLocationAccessPermission() }
        tv_privacy_notice.setOnClickListener {
            _appNavigator.openInChrome(
                context!!,
                Constants.PRIVACY_URL
            )
        }
    }

    override fun invalidate() = withState(_viewModel) { state ->
        binding.run {
            buttonOneText = state.onBoardingContent.button1Text
            buttonTwoText = state.onBoardingContent.button2Text
            imageHelpText = state.onBoardingContent.imageHelpText
            imageText = state.onBoardingContent.imageText
            imageUrl = state.onBoardingContent.imageUrl
        }
    }

    private fun handleLocationAccessPermission() = activity?.let {
        _permissionProvider.checkSelfPermission(
            it,
            permission = Manifest.permission.ACCESS_FINE_LOCATION,
            requestPermission = { requestPermission() },
            granted = {
                findNavController().navigate(R.id.next_action_b)
            },
            shouldShowExplanation = { showDialog() })
    }

    private fun showDialog() {
        val fm = fragmentManager
        fm ?: return
        val dialogFragment = LocationAccessDialogFragment.newInstance()
        dialogFragment.show(fm, "locationAccessDialog")
        dialogFragment.callback = object : LocationAccessDialogFragment.Callback {
            override fun onAllow() {
                requestPermission()
            }
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        when (requestCode) {
            PermissionProvider.REQUEST_CODE -> {
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    findNavController().navigate(R.id.next_action_b)
                }
            }
        }
    }

    private fun requestPermission() = requestPermissions(
        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
        PermissionProvider.REQUEST_CODE
    )
}
这是我的测试

@Test
fun a_checkBtnAccessLocationClickForDenyPermission() {
        val scenario = launchFragmentInContainer<LocationAccessFragment>()
        scenario.onFragment { fragment ->
            Navigation.setViewNavController(fragment.requireView(), navController)
        }

        onView(withId(R.id.access_location)).perform(click())
    }
}
@测试
乐趣a_checkbtAccessLocation单击获取权限(){
val场景=launchFragmentInContainer()
scenario.onFragment{fragment->
Navigation.setViewNavController(fragment.requireView(),navController)
}
onView(带id(R.id.access\u location))。执行(单击())
}
}

在showDialog()方法更改行的主要活动中

val fm=fragmentManager


我希望它能帮助您

我假设您希望对片段执行单元测试,在这种情况下,您应该对DialogFragment执行单独的单元测试

片段单元测试看起来像这样

@Test
fun a_checkBtnAccessLocationClickForDenyPermission() {
        val mockNavController = mock(NavController::class.java)
        val scenario = launchFragmentInContainer<LocationAccessFragment>()
        scenario.onFragment { fragment ->
            Navigation.setViewNavController(fragment.requireView(), mockNavController)
        }

        onView(withId(R.id.access_location)).perform(ViewActions.click())
        verify(mockNavController).navigate(R.id.actoin_fragment_to_locationAccessDialog)

    }
}

你让它工作了吗?面临类似问题
val fm=childFragmentManager
@Test
fun a_checkBtnAccessLocationClickForDenyPermission() {
        val mockNavController = mock(NavController::class.java)
        val scenario = launchFragmentInContainer<LocationAccessFragment>()
        scenario.onFragment { fragment ->
            Navigation.setViewNavController(fragment.requireView(), mockNavController)
        }

        onView(withId(R.id.access_location)).perform(ViewActions.click())
        verify(mockNavController).navigate(R.id.actoin_fragment_to_locationAccessDialog)

    }
}
@Test
fun positiveButton() {
    
    launchFragment(themeResId = R.style.My_theme) {
        return@launchFragment LocationAccessDialogFragment() 
    }

    onView(allOf(withId(android.R.id.button1), withText(R.string.confirm)))
       .inRoot(isDialog())
       .check(matches(isDisplayed()))
       .perform(ViewActions.click())
    
}