.opencode/skills/testing/SKILL.md
Write tests correctly in Android projects. Use this skill when writing any type of tests (unit, integration, UI), testing business logic, network functions, and UI components.
npx skillsauth add easydev991/Jetpack-WorkoutApp testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use the make test command to run all unit tests:
make test
This command:
./gradlew test --console=plain - all unit tests (JVM, without device)scripts/test_report.py script after test completionThe scripts/test_report.py script generates a detailed test results report:
Example script output:
================================================================================
✅ BUILD SUCCESSFUL
================================================================================
Test Statistics:
Total tests: 145
✅ Passed: 142
❌ Failed: 3
❌ List of failed tests:
- AuthViewModelTest::login_withInvalidCredentials_returnsError
- EventsViewModelTest::loadEvents_whenNetworkError_returnsError
- ParksRepositoryImplTest::getParks_whenEmpty_returnsEmptyList
================================================================================
Statistics by test classes (5 classes):
================================================================================
Class Failed Passed Total
----------------------------------------------------------------------------
AuthViewModelTest 1 12 13
EventsViewModelTest 1 8 9
ParksRepositoryImplTest 1 15 16
================================================================================
make android-test - run integration tests on Android devicemake test-all - run all tests (unit + integration)make android-test-report - open HTML integration test report in browserapp/src/test/ - unit tests (ViewModels, Use Cases, Domain models)app/src/androidTest/ - integration/UI tests (DAO, Repository, UI components)*TestImportant: Recommendations for ViewModel integration tests
runTest, MainDispatcherRule, and TurbineWhy unit tests with MockK are preferred:
When to use ViewModel integration tests:
Important: ViewModels using viewModelScope.launch require MainDispatcherRule in tests. viewModelScope runs on Dispatchers.Main, which is not configured by default in Unit tests. Without MainDispatcherRule, coroutines won't be able to start, and state checks will be incorrect.
Creating MainDispatcherRule:
@ExperimentalCoroutinesApi
class MainDispatcherRule(
private val testDispatcher: TestDispatcher = StandardTestDispatcher()
) : TestWatcher() {
override fun starting(description: Description) {
Dispatchers.setMain(testDispatcher)
}
override fun finished(description: Description) {
Dispatchers.resetMain()
}
}
Example unit test:
@ExperimentalCoroutinesApi
class AuthViewModelTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
private lateinit var viewModel: AuthViewModel
private val loginUseCase: LoginUseCase = mockk()
@Before
fun setup() {
viewModel = AuthViewModel(loginUseCase)
}
@Test
fun login_whenValidCredentials_thenReturnsSuccess() = runTest {
// Given
val credentials = LoginCredentials("[email protected]", "password")
coEvery { loginUseCase(credentials) } returns Result.success(loginSuccess)
// When
viewModel.login()
advanceUntilIdle()
// Then
assertTrue(viewModel.uiState.value is LoginUiState.Idle)
}
}
Use real in-memory database for DAO tests:
@RunWith(AndroidJUnit4::class)
class ParksDaoTest {
private lateinit var database: AppDatabase
private lateinit var parksDao: ParksDao
@Before
fun createDb() {
database = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
AppDatabase::class.java
).allowMainThreadQueries().build()
parksDao = database.parksDao()
}
@After
@Throws(IOException::class)
fun closeDb() {
database.close()
}
@Test
fun insertAndGetPark() = runTest {
// Given
val park = ParkEntity(/* ... */)
// When
parksDao.insert(park)
val loaded = parksDao.getById(park.id)
// Then
assertEquals(park, loaded)
}
}
@RunWith(AndroidJUnit4::class)
class LoginScreenTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun loginScreen_showsEmailField() {
composeTestRule.setContent {
LoginScreen()
}
composeTestRule
.onNodeWithText("Email")
.assertIsDisplayed()
}
}
Mock example:
@Test
fun loadParks_whenSuccess_thenReturnsParks() = runTest {
// Given
val mockParks = listOf(Park(/* ... */))
coEvery { api.getParks() } returns Response.success(mockParks)
// When
val result = repository.getParks()
// Then
assertEquals(mockParks, result)
}
Mocking HttpException:
@Test
fun loadParks_whenNetworkError_thenReturnsError() = runTest {
// Given
val httpException = HttpException(
Response.error<Any>(404, "Not found".toResponseBody())
)
coEvery { api.getParks() } throws httpException
// When
val result = repository.getParks()
// Then
assertTrue(result.isFailure)
}
Important: For Flows with exceptions handled via catch, use first() or collect() instead of Turbine.
Testing IOException (handled in catch):
@Test
fun loadData_whenIOException_thenReturnsErrorState() = runTest {
// Given
coEvery { repository.getData() } throws IOException("Network error")
// When
val result = useCase().first()
// Then
assertTrue(result.isFailure)
}
Testing other exceptions (propagated):
@Test(expected = IllegalStateException::class)
fun loadData_whenIllegalState_thenThrows() = runTest {
// Given
coEvery { repository.getData() } throws IllegalStateException()
// When
useCase().first()
}
Mocking Android Log:
@Before
fun setup() {
mockkStatic(Log::class)
every { Log.d(any(), any()) } returns 0
every { Log.e(any(), any()) } returns 0
}
@Test, @Before, @After)assertEquals, assertTrue, assertNull)testing
Пиши тесты в андроид-проекте правильно. Используй этот навык при написании любых типов тестов (unit, integration, UI), тестировании бизнес-логики, сетевых функций и компонентов UI.
tools
Реализуй pull-to-refresh в Jetpack Compose с использованием Material 3 PullToRefreshBox. Используй этот навык при добавлении возможности обновления данных на экранах со списками или карточками.
tools
Правильно работай с локализацией в Android-проекте. Используй этот навык при добавлении новых строковых ресурсов, работе с plurals, форматировании дат и текстов.
tools
Блокировка UI контента экрана во время загрузки данных или выполнения асинхронных операций с отображением индикатора загрузки. Используй этот навык при разработке экранов с сетевыми запросами, операциями CRUD и других асинхронных действий.