Skip to content

Commit

Permalink
Screenshot tests edited (#564)
Browse files Browse the repository at this point in the history
* TECH: add screenshot-tests-1 lesson

* Update tutorial.yml

* TECH: edit Screenshot_tests_2.en.md

---------

Co-authored-by: Azamat Cherchesov <[email protected]>
  • Loading branch information
sumin93 and AzamatCherchesov authored Oct 9, 2023
1 parent 0fa58e6 commit 76bd072
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 250 deletions.
73 changes: 25 additions & 48 deletions docs/Tutorial/Screenshot_tests_1.en.md

Large diffs are not rendered by default.

44 changes: 27 additions & 17 deletions docs/Tutorial/Screenshot_tests_2.en.md

Large diffs are not rendered by default.

33 changes: 21 additions & 12 deletions docs/Tutorial/Screenshot_tests_2.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {

@Test
fun takeScreenshots() {

}
}

Expand Down Expand Up @@ -191,6 +191,8 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {

```

На этом этапе уже можно видеть одну проблему - мы загружаем данные из сети, в зависимости от скорости интернета и от работоспособности сервера скорость загрузки может меняться. Есть большая вероятность, что данные о пользователе будут загружены почти мгновенно, и состояние загрузки вы вообще не увидите, оно не будет сохранено на скриншотах, и тест упадет, потому что проверка на `progressBarLoading.isVisible` никогда не вернет значение true. Решение этой проблемы мы разберем далее в этом уроке.

Следующий этап – отображение данных о пользователе (стейт Content)

```kotlin
Expand Down Expand Up @@ -223,7 +225,7 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {
}

```
Теперь нам нужно получить состояние ошибки. В реальных приложениях можно было бы, например, выключить интернет на устройстве и выполнить запрос. В текущей реализации приложения мы лишь имитируем работу с интернетом, и для получения ошибки можно еще дважды попробовать загрузить данные пользователя. Имейте в виду, что это временная реализация, позже мы ее исправим.
Теперь нам нужно получить состояние ошибки. Как вариант, мы можем отключить интернет на устройстве, затем кликнуть по кнопке и увидеть сообщение об ошибке. Тогда нужно не забывать перед проведением тестирования, а также после него включать интернет, чтобы наш тест всегда запускался в необходимых условиях, а также не влиял на другие тесты. После включения и выключения теста добавим небольшой таймаут, чтобы быть уверенным, что интернет-подключение перешло в нужное нам состояние.

```kotlin
package com.kaspersky.kaspresso.tutorial.screenshot_tests
Expand All @@ -243,43 +245,45 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {
@Test
fun takeScreenshots() {
LoadUserScreen {
device.network.enable()
Thread.sleep(5000)
loadingButton.isVisible()
captureScreenshot("Initial state")
loadingButton.click()
progressBarLoading.isVisible()
captureScreenshot("Progress state")
username.isVisible()
captureScreenshot("Content state")
device.network.disable()
Thread.sleep(3000)
loadingButton.click()
progressBarLoading.isVisible()
username.isVisible()
loadingButton.click()
progressBarLoading.isVisible()
error.isVisible()
captureScreenshot("Error state")
device.network.enable()
Thread.sleep(5000)
}
}
}

```


## Проблемы текущего подхода

Таким образом, мы смогли написать скриншот тест, в котором получили все необходимые состояния экрана, имитируя действия пользователя – кликая по кнопке и ожидая результата выполнения запроса. Но давайте подумаем, насколько эта реализация подойдет для реальных приложений.

Если мы работаем с реальным приложением, то после клика на кнопку тест будет ждать, пока запрос не вернет какой-то ответ с сервера. Если интернет будет медленным, или на сервере будут наблюдаться какие-то проблемы, то и время ожидания ответа может сильно увеличиться, соответственно будет увеличено время выполнения теста. При этом обратите внимание, что тест будет выполнен для каждой локали, которую мы передали в качестве параметра конструктора `DocLocScreenshotTestCase`, и каждый из этих тестов будет зависеть от скорости интернет-соединения и от работоспособности сервера.
1. Состояние прогресса зависит от скорости интернет-соединения и от работоспособности сервера. Если ответ вернется очень быстро, то состояние прогресса мы никогда не получим, и наш тест завершится неудачно.

Также сервер может вернуть ошибку, когда мы ее не ожидали, в этом случае тест завершится неудачно.
2. Для получения состояния ошибки мы отключаем интернет на устройстве, но в реальных приложениях часто бывает ситуация, когда в зависимости от типа ошибки поведение приложения должно отличаться. Например, если на устройстве нет интернета, то нужно показать сообщение пользователю, чтобы он включил интернет, а если сервер вернул какую-то ошибку, то отобразить соответствующий диалог. В этом случае сымитировать состояние ошибки в приложении становится очень сложной задачей.

На определенном этапе теста мы хотим сделать скриншот состояния ошибки. В данном случае мы одинаково реагируем на любой тип ошибки, показывая строчку «Что-то пошло не так», но часто бывают случаи, когда пользователю нужно сообщать о том, что конкретно произошло. Например, при отсутствии интернета, показать уведомление об этом, при ошибке на сервере показать соответствующий диалог и так далее. Поэтому в каких-то случаях для воспроизведения стейта с ошибкой будет достаточно отключить интернет на устройстве, а в каких-то это может стать проблемой, которую не так просто решить.
3. Цель «скриншотилки» - сделать снимки всех возможных состояний экрана, а не проверить работоспособность приложения. Тем не менее, если в момент проведения теста будут какие-то проблемы с интернетом, или сервер не будет отвечать на запросы, то при такой реализации тест завершится неудачно, и никаких снимков мы не получим.

Так мы приходим к следующему выводу: получить все необходимые стейты, имитируя действия пользователя, для скриншот-тестов нецелесообразно.

Во-первых, это может сильно замедлить выполнение теста.
Во-первых, некоторые состояние экрана получить очень сложно или даже невозможно.

Во-вторых, такие тесты начинают зависеть от многих факторов, таких как скорость интернета и работоспособность сервера, следовательно вероятность того, что эти тесты завершатся неудачно, возрастает.

В-третьих, некоторые состояния экрана получить очень сложно, и этот процесс может занять длительное время

## Взаимодействие View и ViewModel

Expand Down Expand Up @@ -474,6 +478,8 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {
androidTestImplementation("io.mockk:mockk-android:1.13.3")
```

<img src="../images/screenshot_tests_2/gradle2.png" alt="Gradle"/>

!!! info
Если после синхронизации и запуска проекта у вас возникают ошибки, следуйте инструкциям в журнале ошибок. В случае, если разобраться не получилось, переключитесь на ветку `TECH-tutorial-results` и сверьте файл `build.gradle` из этой ветки с вашим

Expand Down Expand Up @@ -770,6 +776,8 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {

Если мы тестируем фрагменты, то запускать активити, в которой этот фрагмент лежит, не нужно. Мы можем напрямую тестировать фрагменты. Для того чтобы у нас была такая возможность, необходимо добавить следующие зависимости в build.gradle

<img src="../images/screenshot_tests_2/gradle.png" alt="Gradle"/>

```kotlin
debugImplementation("androidx.fragment:fragment-testing-manifest:1.6.0"){
isTransitive = false
Expand Down Expand Up @@ -833,7 +841,7 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {

## Меняем стиль

Вы могли обратить внимание, что внешний вид экрана в приложении отличается от того, который мы получили в результате выполнения теста. Проблема заключается в использовании стилей. Во время теста под капотом создается активити, которая является контейнером для нашего фрагмента. Стиль этой активити может отличаться от того, который используется у нас в приложении.
Вы могли обратить внимание, что внешний вид экрана в приложении отличается от того, который мы получили в результате выполнения теста. Проблема заключается в использовании [стилей]( https://developer.android.com/develop/ui/views/theming/themes). Во время теста под капотом создается активити, которая является контейнером для нашего фрагмента. Стиль этой активити может отличаться от того, который используется у нас в приложении.

Данная проблема решается очень просто – в качестве параметра в метод `launchFragmentInContainer` можно передать стиль, который должен использоваться внутри фрагмента, его можно найти в манифесте приложения

Expand Down Expand Up @@ -889,3 +897,4 @@ class LoadUserScreenshots : DocLocScreenshotTestCase(locales = "en, fr") {
## Итог

Это был очень насыщенный урок, в котором мы научились правильно устанавливать стейты во вьюмодель, тестировать фрагменты, использовать бибилотеку Mockk для мокирования сущностей, а также дорабатывать код приложения, чтобы его можно было покрыть screenshot-тестами.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
84 changes: 1 addition & 83 deletions docs/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ And many more!

<img src="kaspresso.png" alt="Kaspresso"/>

<details>
<summary>

## Integration
</summary>

To integrate Kaspresso into your project:
1. If the `mavenCentral` repository does not exist, include it to your root `build.gradle` file:
Expand Down Expand Up @@ -79,25 +75,16 @@ dependencies {
}
```

</details>

## FAQ
For all questions you can reach out to us on [Discord](https://kas.pr/gh_discord).

## Tutorial *NEW*
To make it easier to learn the framework, a step-by-step tutorial is available on [our website](https://kasperskylab.github.io/Kaspresso/Tutorial/).

<details>
<summary>

## Capabilities of Kaspresso
</summary>

<details>
<summary>

### Readability
</summary>

We like the syntax that [Kakao](https://github.com/KakaoCup/Kakao) applies to write UI tests. This wrapper over Espresso uses the Kotlin DSL approach, that makes the code
significantly shorter and more readable. See the difference:

Expand Down Expand Up @@ -204,39 +191,21 @@ fun shouldPassOnNoInternetScanTest() =
}
```

</details>

<details>
<summary>

### Stability
</summary>

Sometimes your UI test passes ten times, then breaks on the eleventh attempt for some mysterious reason. It’s called *flakiness*.

The most popular reason for flakiness is the instability of the UI tests libraries, such as Espresso and UI Automator. To eliminate this instability, Kaspresso uses DSL wrappers and [interceptors](#Interceptors).

</details>

<details>
<summary>

### UI test libraries acceleration
</summary>

Let’s watch some short video that shows the difference between the original UI Automator (on the right) and the accelerated one (on the left).

![](https://habrastorage.org/webt/ti/kv/ki/tikvkij1vjesnacrxqm-lk0coly.gif)

Here is [a short explanation](https://kasperskylab.github.io/Kaspresso/Wiki/Kautomator-wrapper_over_UI_Automator/#accelerate-ui-automator) of why it is possible.

</details>

<details>
<summary>

### Interceptors
</summary>

We developed [Kaspresso behavior interceptors](https://kasperskylab.github.io/Kaspresso/Wiki/Kaspresso_configuration/#some-words-about-behavior-interceptors) on the base of [Kakao/Kautomator
Interceptors](https://kasperskylab.github.io/Kaspresso/Wiki/Kaspresso_configuration/#kaspresso-interceptors-based-on-kakaokautomator-interceptors) to catch failures.
Expand All @@ -248,36 +217,18 @@ Thanks to interceptors, you can do a lot of useful things, such as:

and many more (see [the manual](https://kasperskylab.github.io/Kaspresso/Wiki/Kaspresso_configuration/#kaspresso-interceptors-based-on-kakaokautomator-interceptors)).

</details>

<details>
<summary>

### Writing readable logs
</summary>

Kaspresso writes its own logs, detailed and readable:

<img src="https://habrastorage.org/webt/03/nn/qg/03nnqgupdqnwa_i4jwyz1uqq6r0.png" />
<img src="https://habrastorage.org/webt/tq/az/3v/tqaz3vjsgpw0-ivylrfbnuqyiqa.png" />

</details>

<details>
<summary>

### Ability to call ADB commands
</summary>

Espresso and UI Automator don't allow to call ADB commands from inside a test. To fix this problem, we developed AdbServer (see the [wiki](https://kasperskylab.github.io/Kaspresso/Wiki/Executing_adb_commands/)).

</details>

<details>
<summary>

### Ability to work with Android System
</summary>

You can use Kaspresso classes to work with Android System.

Expand All @@ -296,66 +247,33 @@ For example, with the ```Device``` class you can:

(see more about the [Device class](https://kasperskylab.github.io/Kaspresso/Wiki/Working_with_Android_OS/)).

</details>

<details>
<summary>

### Features screenshotting
</summary>

If you develop an application that is available across the world, you have to *localize* it into different languages. When UI is localized, it’s important for the translator to see the context of a word or a phrase, that is the specific screen.

With Kaspresso, translators can automatically take a screenshot of any screen. It’s incredibly fast, even for legacy screens, and you don't have to refactor or mock anything (see [the manual](https://kasperskylab.github.io/Kaspresso/Wiki/Screenshot_tests/)).

</details>

<details>
<summary>

### Configurability
</summary>

You can tune any part of Kaspresso (read [more](https://kasperskylab.github.io/Kaspresso/Wiki/Kaspresso_configuration/)).

</details>

<details>
<summary>

### Robolectric support
</summary>

You can run your UI-tests on the JVM environment. Additionally, almost all interceptors improving stability, readability and other will work.
Read [more](https://kasperskylab.github.io/Kaspresso/Wiki/Kaspresso_Robolectric/).

</details>

<details>
<summary>

### Allure support
</summary>

Kaspresso can generate very detailed Allure-reports for each test:
![](https://habrastorage.org/webt/tq/t7/ch/tqt7chcdczrgduhoukqhx1ertfc.png)
More information is available [here](https://kasperskylab.github.io/Kaspresso/Wiki/Kaspresso_Allure/).

</details>

<details>
<summary>

### Jetpack Compose support
</summary>

Now, you can write your Kaspresso tests for Jetpack Compose screens! DSL and all principles are the same.
So, you will not see any difference between tests for View screens and for Compose screens.
More information is available [here](https://kasperskylab.github.io/Kaspresso/Wiki/Jetpack_Compose/).

</details>
</details>

## Samples
All samples are available in the [samples](https://github.com/KasperskyLab/Kaspresso/tree/master/samples) folder.

Expand Down
Loading

0 comments on commit 76bd072

Please sign in to comment.