Я пытаюсь написать тест Espresso UI для сборки приложения для Android с kotlin.Я написал базовый тест пользовательского интерфейса для проверки элементов пользовательского интерфейса, присутствующих в элементе loginFragment.
@LargeTest
class LoginFragmentTest {
private val serverUrl = "https://example.com"
@JvmField
var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true)
@Rule
fun rule() = activityRule
@Before
fun setUp() {
rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) {
newInstance(serverUrl)
}
}
@Test
fun check_UI_elements(){
onView(withId(R.id.text_login)).check(matches(withText("Login")))
onView(withId(R.id.text_username_or_email)).check(matches(withHint("Username or email")))
onView(withId(R.id.text_password)).check(matches(withHint("Password")))
onView(withId(R.id.button_log_in)).check(matches(withText("Login")))
onView(withId(R.id.button_forgot_your_password)).check(matches(withText("Forgot your password?")))
}
Фрагмент входа в систему
class LoginFragment : Fragment(), LoginView {
@Inject
lateinit var presenter: LoginPresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private var serverName: String? = null
private val editTextsDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
arguments?.run {
serverName = getString(SERVER_NAME)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_authentication_log_in)
.....
}
Вход в систему Presenter
class LoginPresenter @Inject constructor(
private val view: LoginView,
private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator,
private val tokenRepository: TokenRepository,
private val localRepository: LocalRepository,
private val settingsInteractor: GetSettingsInteractor,
private val analyticsManager: AnalyticsManager,
private val saveCurrentServer: SaveCurrentServerInteractor,
private val saveAccountInteractor: SaveAccountInteractor,
private val factory: RocketChatClientFactory,
val serverInteractor: GetConnectingServerInteractor
) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
fun setupView() {
setupConnectionInfo(currentServer)
setupForgotPasswordView()
}
...
}
Я такжеесть SaveConnectingServerInteractor и GetConnectingServerInteractor, который используется для хранения URL-адреса сервера во время аутентификации.
open class SaveConnectingServerInteractor @Inject constructor(
@ForAuthentication private val repository: CurrentServerRepository
) {
fun save(url: String) = repository.save(url)
}
open class GetConnectingServerInteractor @Inject constructor(
@ForAuthentication private val repository: CurrentServerRepository
) {
fun get(): String? = repository.get()
fun clear() {
repository.clear()
}
}
LoginFragmentModule
@Module
class LoginFragmentModule {
@Provides
@PerFragment
fun loginView(frag: LoginFragment): LoginView = frag
@Provides
@PerFragment
fun provideLifecycleOwner(frag: LoginFragment): LifecycleOwner = frag
}
LoginFragmentProvider
@Module abstract class LoginFragmentProvider {
@ContributesAndroidInjector(modules = [LoginFragmentModule::class])
@PerFragment
abstract fun provideLoginFragment(): LoginFragment
}
Но при запускетест Я получаю KotlinNullPointerException, так как переменная currentServer становится нулевой, потому что в ней нет сохраненного URL.Есть ли способ избежать обнуления во время выполнения теста пользовательского интерфейса.Я попытался с помощью оператора elvis и изменить LoginPresenter, но я хочу знать, есть ли другой способ, который может работать.Я просто хочу инициализировать значение текущего сервера любой строкой URL, чтобы избежать NPE во время выполнения тестов.
Я также пытался использовать
@Before
fun setUp() {
`when`(serverInteractor.get()).thenReturn("http://fakeurl")`
rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) {
newInstance(serverUrl)
}
}
, но затем он выбрасывает
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String chat.rocket.android.server.domain.CurrentServerRepository.get()' on a null object reference
at chat.rocket.android.server.domain.GetConnectingServerInteractor.get(GetConnectingServerInteractor.kt:9)
at chat.rocket.android.authentication.login.ui.LoginFragmentTest.setUp(LoginFragmentTest.kt:42)