Kaspresso: Android UI Testing with Kakao DSL and Allure Reports

Kaspresso: Android UI Testing with Kakao DSL and Allure Reports

Kaspresso is an Android UI test framework built on top of Espresso and UIAutomator. It solves the two biggest problems with raw Espresso: flaky tests and unreadable test code. With Kaspresso, you get a clean Kotlin DSL (via Kakao), automatic waiting and retry logic, and first-class Allure report integration.

If your Espresso tests are brittle or your test output is hard to parse, Kaspresso fixes both.

Why Kaspresso Over Raw Espresso

Espresso is fast and accurate, but it has rough edges:

  • View synchronization works well for simple cases but breaks with custom async loading patterns
  • Test failures produce cryptic stack traces with no screenshots
  • Test code becomes verbose for even simple interactions
  • UIAutomator integration requires manual boilerplate

Kaspresso wraps all of this with a more stable runtime and a readable DSL.

Setup

Add to build.gradle.kts (app module):

dependencies {
    androidTestImplementation("com.kaspersky.android-components:kaspresso:1.5.3")
    androidTestImplementation("com.kaspersky.android-components:kaspresso-allure-support:1.5.3")
    // Kakao DSL (bundled, but explicit import helps IDE)
    androidTestImplementation("io.github.kakaocup:kakao:3.0.6")
}

Screen Objects with Kakao DSL

Kakao uses a Screen abstraction — define your screen's interactive elements once, reuse across tests.

object LoginScreen : Screen<LoginScreen>() {
    val emailField = KEditText { withId(R.id.email) }
    val passwordField = KEditText { withId(R.id.password) }
    val loginButton = KButton { withId(R.id.login_button) }
    val errorMessage = KTextView { withId(R.id.error_text) }
}

This is cleaner than Espresso's onView(withId(...)) scattered through test methods.

Writing a Kaspresso Test

class LoginTest : TestCase() {

    @get:Rule
    val activityRule = ActivityScenarioRule(LoginActivity::class.java)

    @Test
    fun loginWithValidCredentials() = run {
        step("Enter credentials") {
            LoginScreen {
                emailField.typeText("user@example.com")
                passwordField.typeText("password123")
                loginButton.click()
            }
        }

        step("Verify dashboard is shown") {
            DashboardScreen {
                welcomeText.isVisible()
                welcomeText.hasText("Welcome back")
            }
        }
    }
}

step() blocks organize test execution into named phases. These map directly to Allure report steps.

Flakiness Prevention

Kaspresso wraps every interaction in an automatic retry loop with configurable timeout. By default, it retries UI interactions for up to 2 seconds before failing.

You can tune this globally:

class MyTest : TestCase(
    kaspressoBuilder = Kaspresso.Builder.simple {
        flakySafetyParams = FlakySafetyParams.simple(
            timeoutMs = 5000,
            intervalMs = 500
        )
    }
)

For specific views that are known to be slow:

flakySafely(timeoutMs = 10000) {
    MyScreen.lazyLoadedItem.isVisible()
}

Allure Integration

Kaspresso has built-in Allure support. Steps, screenshots, and logs are automatically captured.

Change the test runner in build.gradle.kts:

android {
    defaultConfig {
        testInstrumentationRunner = "com.kaspersky.android-components.kaspresso.alluresupport.AllureAndroidJUnitRunner"
    }
}

Run tests and pull results:

./gradlew connectedAndroidTest
adb pull /sdcard/allure-results ./allure-results
allure serve ./allure-results

The report shows each step() with screenshots on failure, device info, and timing.

ADB Server Mode

Kaspresso can communicate with the host machine via ADB during tests. This enables advanced scenarios like:

  • Simulating network conditions
  • Toggling device settings (airplane mode, GPS, notifications)
  • Uploading files to the device mid-test

Enable it in your test configuration:

class NetworkTest : TestCase(
    kaspressoBuilder = Kaspresso.Builder.simple {
        adbServer = AdbServerImpl(adbServerPort = AdbServer.DEFAULT_PORT)
    }
) {
    @Test
    fun testOfflineMode() = run {
        step("Enable airplane mode") {
            device.network.toggleAirplaneMode(true)
        }

        step("Verify offline message") {
            HomeScreen.offlineMessage.isVisible()
        }

        step("Restore connectivity") {
            device.network.toggleAirplaneMode(false)
        }
    }
}

ADB server requires the adbserver-desktop.jar running on the host during test execution.

Interceptors

Kaspresso supports interceptors — hooks that fire before and after every UI interaction. Use them for custom logging, screenshots on every step, or additional assertions.

Kaspresso.Builder.simple {
    viewInterceptors += object : ViewInteractionInterceptor {
        override fun onAll(interaction: ViewInteraction) {
            Allure.addAttachment("screenshot", takeScreenshot())
        }
    }
}

Comparing to Espresso

Feature Espresso Kaspresso
DSL readability Low — verbose matcher chains High — Kakao screen objects
Flakiness handling Manual waits Built-in retry
Screenshots on failure None by default Automatic with Allure
Step reporting None Named steps in reports
UIAutomator support Separate boilerplate Integrated

What to Test with Kaspresso

Kaspresso is best for:

  • Login / auth flows — multiple screens, form validation, error states
  • Onboarding sequences — multi-step with state transitions
  • Settings screens — toggles, pickers, navigation
  • Any test you've had to add Thread.sleep() to — replace with flakySafely

For unit-layer tests or Compose UI, use other tools (Robolectric or Compose testing APIs). Kaspresso targets View-based UI on real devices or emulators.

Summary

Kaspresso makes Android UI tests maintainable. The Kakao DSL reduces noise in test code, the retry logic eliminates most flakiness, and Allure integration gives you readable failure reports without extra tooling. If you're writing Espresso tests today and they're fragile or hard to read, migrating to Kaspresso is a straightforward upgrade.

Read more