marp | theme | transition | style |
---|---|---|---|
true |
gaia |
fade |
img[alt="1"] {
view-transition-name: one;
contain: layout;
}
img:is([alt="1"], [alt="2"], [alt="3"], [alt="4"], [alt="5"]) {
height: 64px;
position: relative;
top: -0.1em;
vertical-align: middle;
width: 64px;
}
|
<style> img[alt~="center"] { display: block; margin: 0 auto; } </style>
Software testing pyramid
- Confidence (Don't repeat your mistakes)
- Continuous deployment
- Screenshots generation
- Application assessment speed up
- Discussion of functionality
- Discussion of assessment criteria
- Feature implementation
- Unit and UI tests implementation
- Validation by QA
- Loading
- Empty
- Reload from Empty
- Content
- Reload from Content
- Error
- Reload from Error
- Cross feature navigation
.../featureA/assesement.yaml
- case:
- id: featureAContentIsDisplayed
- scenario:
Open Feature A screen
Wait for Content
Verify that Loading is not displayed
Verify that Error is not displayed
Verify that 3 items displayed in list
Verify 1 item title is equals "Test title 1"
Verify 2 item title is equals "Test title 2"
Verify 3 item title is equals "Test title 3"
<style> img[alt~="center"] { display: block; margin: 0 auto; } </style>
- How to write?
- Native / Cross platform
- Content / Screenshot
- How to run?
- Locally / Remotely
- Environment
- How to scale?
- Run in parallel
Espresso | Kakao | Kaspresso |
---|---|---|
![]() |
![]() |
Pros | Cons |
---|---|
✅ Supported by Google | ❌ Lots of boilerplate |
✅ Native Android test library | ❌ Depends on API version |
✅ Most popular UI testing framework | ❌ Resources assertion and matching not supported out of the box |
✅ Fast |
Pros | Cons |
---|---|
✅ Testing for ADB calls such as SMS, Calls, Geolocation etc | ❌ Requires ADB server |
✅ Built-in flakiness retries | ❌ Tricky for scaling |
✅ Allure report | ❌ Parallel runs on CI |
✅ Steps support | |
✅ Based on Kakao |
- Espresso
onView(allOf(withId(R.id.price_item),hasDescendant(withText("Standard Rate"))))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
- Kakao
onScreen<FormScreen> {
price {
isVisible()
}
}
class FormScreen : Screen<FormScreen>() {
val phone = KEditText { withId(R.id.phone) }
val email = KEditText { withId(R.id.email) }
val submit = KButton { withId(R.id.submit) }
}
onScreen<FormScreen> {
phone {
hasText("971201771")
}
submit {
click()
}
}
class Item(parent: Matcher<View>) : KRecyclerItem<Item>(parent) {
val title: KTextView = KTextView(parent) { withId(R.id.title) }
}
val recycler: KRecyclerView = KRecyclerView(
{ withId(R.id.recycler_view) },
itemTypeBuilder = { itemType(::Item) })
onScreen<RecyclerScreen> {
recycler {
firstChild<Item> {
title { hasText("Title 1") }
...
class MainActivityScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<MainActivityScreen>(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag("MainScreen") }
) {
val myButton: KNode = child {
hasTestTag("myTestButton")
}
val myButton2: KNode = myButton.child {
hasTestTag("myTestButton2")
}
}
class ExampleInstrumentedTest {
@Rule
@JvmField
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Test
fun simpleTest() {
onComposeScreen<MainActivityScreen>(composeTestRule) {
myButton {
assertIsDisplayed()
assertTextContains("Button 1")
}
onNode { hasTestTag("doesNotExist") }.invoke {
assertDoesNotExist()
}
}
}
}
.../featureA/assessment.yaml
- case:
- id: featureAContentIsDisplayed
- scenario:
Open Feature A screen
Wait for Content
Verify that Loading is not displayed
Verify that Error is not displayed
Verify that 3 items displayed in list
Verify 1 item title is equals "Test title 1"
Verify 2 item title is equals "Test title 2"
Verify 3 item title is equals "Test title 3"
@Test
fun featureAContentIsDisplayed()
onScreen<FeatureAScreen> {
waitFor(R.id.title)
loading { isNotDisplayed() }
error { isNotDisplayed() }
list {
isDisplayed()
childAt(0)<Item> { title { hasText("Test title 1") } }
childAt(1)<Item> { title { hasText("Test title 2") } }
childAt(2)<Item> { title { hasText("Test title 3") } }
}
}
Kakao | Marathon |
---|---|
✅ Nice and simple DSL | ✅ Flakiness control strategies |
✅ Typed page objects | ✅ Easy to scale |
✅ Recycler support | ✅ Can be integrated with CI |
✅ Compat API support | ✅ Supports custom configurations for your needs |
✅ Lots of Matcher and Assertions | ✅ Allure reporting |
- What are we testing?
- Feature
- Integration
- Why do we need mocks?
- Performance improvement
- Tests results stability
- Control for 3rd party code
- Deployment
- Local
- Remote
- Type
- Stateless
- Stateful
Pros | Cons |
---|---|
✅ Testing whole HTTP stack | ❌ Extra time for request-response processing |
✅ Good for Integration testing | ❌ Bad for Feature testing |
❌ Stateful | |
❌ Unstable results and branching in tests logic |
Pros | Cons |
---|---|
✅ Testing whole HTTP stack | ❌ Extra time for request-response processing |
✅ Single remote instance | ❌ Required redeploy in case of mock updates |
✅ Stable results for UI testing | ❌ Not supporting custom error codes |
✅ Stateless |
Pros | Cons |
---|---|
✅ Easy to implement | ❌ HTTP Stack not tested |
✅ Fast responses | ❌ Not shared between platforms |
✅ Static mock going as part of application | |
✅ Can be executed anywhere |
- Custom
TestRule
's for custom behaviours- Response codes
- Throttling
- Responses aligned with Test Suits requirements
Pros | Cons |
---|---|
✅ HTTP Stack tested | ❌ Requires extra effort to implement |
✅ Mocks responses in-app | ❌ Unsynchronized with "Production server" |
✅ Good for Features test | ❌ Bad for Integration test |
✅ Can be run as "Remote server" | |
✅ Customizable behaviours |
- Always understand what you want to test
- Choose the right tooling set
- Ask yourself "How will this code change in 3 years"
- Think about scaling
- Questions?