多模块android应用中的测试结构

Testing structure in multi-module android application

提问人:Sergi Poza Paterna 提问时间:11/17/2023 更新时间:11/17/2023 访问量:6

问:

我对在 Android 中的测试有点困惑。我对 e2e 和集成测试感到困惑,我不知道我应该将它们放在哪个模块(数据、域或演示文稿)中。

据我了解,e2e 测试整个系统的行为是否符合其部署方式。例如,验证当我将有效凭据放在登录屏幕上时,它是否登录并重定向到另一个屏幕。而且,集成测试的重点是测试不同组件的集成,例如存储库与数据源(如数据库或其他)的交互。

因此,我对何时应该进行 e2e 或集成测试有疑问。假设我有一个登录屏幕,其中包含一个 View an VM 类。 我应该为 View(e2e 期望登录行为)和 VM(集成期望状态正确更新并且存储库按预期响应)创建不同的测试,还是只是检查整个登录系统是否正常工作的 e2e 测试?

此外,我一直在思考我应该如何在不同的模块中组织所有这些测试,以

一个集成测试,用于验证用例是否与模拟存储库正确交互

private lateinit var authRepository: AuthRepository
private lateinit var loginUsecase: LoginUsecase

@ExperimentalCoroutinesApi
@get:Rule
var mainCoroutineRole = MainCoroutineRole()

@BeforeEach
fun setup() {
    mockkClass(AuthRepository::class)

    authRepository = mockk()
    loginUsecase = LoginUsecase(authRepository)
}

@Test
fun `login with valid credentials returns user`() = runBlocking {
    val expected = User(username = "spozap", password = "P@ssw0rd!")
    coEvery { authRepository.login(expected.username, expected.password) } returns flow { Resource.Success(expected) }
    loginUsecase("spozap", "P@ssw0rd!")

    coVerify { authRepository.login("spozap", "P@ssw0rd!") }
}

验证用例的一些单元:

private lateinit var validatePasswordUsecase: ValidatePasswordUsecase

@BeforeEach
fun init() {
    validatePasswordUsecase = ValidatePasswordUsecase()
}

@Test
fun `it returns validation error with NOT_NULL_FILLED code when empty password`() {
    val result = validatePasswordUsecase("")
    val expected = ValidationResult( successful = false, errorMessage = ValidationError.NOT_NULL_FIELD )
    assertThat(result).isEqualTo(expected)
}

@Test
fun `it returns successful validation result with no errorMessage when password is valid`() {
    val result = validatePasswordUsecase("P@ssw0rd!")
    val expected = ValidationResult(successful = true, errorMessage = null)
    assertThat(result).isEqualTo(expected)
}

还有一个 UI 测试

private lateinit var navController: NavHostController

@get:Rule(order = 0)
val hiltRule = HiltAndroidRule(this)

@get:Rule(order = 1)
val composeRule = createAndroidComposeRule<MainActivity>()


@Before
fun setup() {
    hiltRule.inject()

    composeRule.activity.setContent {
        navController = rememberNavController()
        AppTheme {
            NavHost(navController = navController, startDestination = AppScreens.Login.route ) {
                composable(route = AppScreens.Login.route) {
                    LoginScreen(navController = navController)
                }
                composable(route = AppScreens.Home.route) {
                    HomeScreen()
                }
            }
        }
    }
}

@Test
fun loginWithValidCredentialsRedirectsToHomeScreen() {
    composeRule.onNodeWithTag(TestTags.USERNAME_INPUT).performTextInput("user1")
    composeRule.onNodeWithTag(TestTags.PASSWORD_INPUT).performTextInput("P@ssw0rd")
    composeRule.onNodeWithText("Entrar").performClick()

    assertThat(navController.currentBackStackEntry?.destination?.route)
        .isEqualTo(AppScreens.Home.route)
}
Android Kotlin 测试 MVVM android-jetpack-compose

评论


答: 暂无答案