Skip to content
android-test-structure logo

android-test-structure

Create androidTest directory structure with base classes and utilities

SKILL.md

Full skill instructions

Android Test Structure

Creates androidTest directory structure with base test class and utilities for Espresso testing.

Prerequisites

  • Android project with Gradle
  • Espresso dependencies added (run android-espresso-dependencies first)
  • Package name known

Inputs

InputRequiredDefaultDescription
project_pathYes.Android project root
package_nameYes-App package (e.g., com.example.app)

Process

Step 1: Create Directory Structure

# Get package path from package name (com.example.app -> com/​example/​app)
PACKAGE_PATH=$(echo "${PACKAGE_NAME}" | tr '.' '/')

# Create androidTest directories
mkdir -p "app/​src/​androidTest/​kotlin/​${PACKAGE_PATH}/​base"
mkdir -p "app/​src/​androidTest/​kotlin/​${PACKAGE_PATH}/​utils"
mkdir -p "app/​src/​androidTest/​kotlin/​${PACKAGE_PATH}/​screens"

Step 2: Create BaseTest.kt

Create app/​src/​androidTest/​kotlin/​${PACKAGE_PATH}/​base/​BaseTest.kt:

package ${PACKAGE_NAME}.base

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.rules.ActivityScenarioRule
import org.junit.After
import org.junit.Before
import org.junit.Rule

/​**
 * Base class for all instrumented tests.
 * Provides common setup, teardown, and utilities.
 */
abstract class BaseTest {

    protected val context: Context = ApplicationProvider.getApplicationContext()

    @Before
    open fun setUp() {
        // Common setup for all tests
        // Override in subclasses for specific setup
    }

    @After
    open fun tearDown() {
        // Common cleanup
        // Override in subclasses for specific cleanup
    }

    /​**
     * Wait for idle state before proceeding
     */
    protected fun waitForIdle() {
        androidx.test.espresso.Espresso.onIdle()
    }
}

Step 3: Create TestUtils.kt

Create app/​src/​androidTest/​kotlin/​${PACKAGE_PATH}/​utils/​TestUtils.kt:

package ${PACKAGE_NAME}.utils

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
import org.hamcrest.Matcher

object TestUtils {

    /​**
     * Custom action to get RecyclerView item count
     */
    fun getRecyclerViewItemCount(recyclerView: RecyclerView): Int {
        return recyclerView.adapter?.itemCount ?: 0
    }

    /​**
     * Wait for a condition with timeout
     */
    fun waitForCondition(
        timeoutMs: Long = 5000,
        condition: () -> Boolean
    ): Boolean {
        val startTime = System.currentTimeMillis()
        while (System.currentTimeMillis() - startTime < timeoutMs) {
            if (condition()) return true
            Thread.sleep(100)
        }
        return false
    }

    /​**
     * Custom ViewAction to perform click on specific position
     */
    fun clickOnViewChild(viewId: Int): ViewAction {
        return object : ViewAction {
            override fun getConstraints(): Matcher<View>? {
                return null
            }

            override fun getDescription(): String {
                return "Click on a child view with specified id."
            }

            override fun perform(uiController: UiController, view: View) {
                val v = view.findViewById<View>(viewId)
                v.performClick()
            }
        }
    }
}

Step 4: Create README for Tests

Create app/​src/​androidTest/​README.md:

# Android E2E Tests

This directory contains end-to-end UI tests using Espresso.

## Structure

- `base/` - Base classes for all tests
- `utils/` - Test utilities and helpers
- `screens/` - Screen-specific test classes

## Running Tests

```bash
# All tests
./​gradlew connectedAndroidTest

# Specific test class
./​gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.app.screens.MainActivityTest

Writing Tests

  1. Extend BaseTest for common setup
  2. Use utilities from TestUtils
  3. Follow AAA pattern: Arrange, Act, Assert

## Verification

**MANDATORY:** Run these commands:

```bash
# Verify directory structure exists
test -d app/​src/​androidTest && echo "✓ androidTest directory created"

# Verify base classes exist
test -f app/​src/​androidTest/​kotlin/​*/​base/​BaseTest.kt && echo "✓ BaseTest.kt created"

# Verify utils exist
test -f app/​src/​androidTest/​kotlin/​*/​utils/​TestUtils.kt && echo "✓ TestUtils.kt created"

Expected output:

  • ✓ androidTest directory created
  • ✓ BaseTest.kt created
  • ✓ TestUtils.kt created

Outputs

OutputLocationDescription
Directory structureapp/​src/​androidTest/Test source directory
BaseTest classbase/​BaseTest.ktCommon test setup
Test utilitiesutils/​TestUtils.ktHelper functions
READMEREADME.mdTest documentation

Troubleshooting

"Package path incorrect"

Cause: Package name format wrong Fix: Use format: com.example.app (not path format)

"Directory already exists"

Cause: androidTest directory already created Fix: Merge with existing structure, don't overwrite

Completion Criteria

  • app/​src/​androidTest/ directory exists
  • base/​BaseTest.kt exists
  • utils/​TestUtils.kt exists
  • screens/ directory exists
  • README.md created