πŸ“± ВСстированиС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ Π² Android с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Kaspresso

ВСстированиС UI Π² Android-прилоТСниях β€” это всСгда баланс ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ‚Ρ‰Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒΡŽ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΠΊ ΠΈ удобством ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ. ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ всё отобраТаСтся ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ β€” Π½Π΅Ρ‚Ρ€ΠΈΠ²ΠΈΠ°Π»ΡŒΠ½Π°Ρ Π·Π°Π΄Π°Ρ‡Π° ΠΈ Ρ‡Π°Ρ‰Π΅ всСго Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ Π½Π° основС Espresso ΡΠΎΡΡ€Π΅Π΄ΠΎΡ‚ΠΎΡ‡ΠΈΠ²Π°ΡŽΡ‚ΡΡ Π»ΠΎΠ³ΠΈΠΊΠ΅ ΠΈ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠΈ: ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡŽΡ‚ тСксты, ΠΊΠ»ΠΈΠΊΠΈ, ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Ρ‹, Ρ†Π²Π΅Ρ‚Π°. Но ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ€Π΅Ρ‡ΡŒ Π·Π°Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΎΠ± изобраТСниях ΠΈΠ»ΠΈ анимациях β€” часто эти ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΠΈΠ»ΠΈ совсСм ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ Π½Π΅Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ, Π»ΠΈΠ±ΠΎ ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ это ΡΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚Π½Ρ‹ΠΌ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ°ΠΌ.

πŸ“± ВСстированиС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ Π² Android с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Kaspresso

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ я ΠΏΠΎΠΊΠ°ΠΆΡƒ, ΠΊΠ°ΠΊ ΠΌΡ‹ пошли Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡƒΡ‚Ρ‘ΠΌ β€” Π½Π°ΡƒΡ‡ΠΈΠ»ΠΈ Kaspresso ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ нарисовано Π½Π° экранС. РасскаТу, ΠΊΠ°ΠΊ ΠΌΡ‹ сравниваСм изобраТСния ΠΈ ΠΊΠ°Π΄Ρ€Ρ‹ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Ρ… инструмСнтов UI-тСстирования β€” Π±Π΅Π· тяТёлой Π°Ρ€Ρ‚ΠΈΠ»Π»Π΅Ρ€ΠΈΠΈ ΠΈ лишнСй хрупкости.

ΠŸΠΎΡ‡Π΅ΠΌΡƒ Π½Π΅ ΡΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚-тСстированиС?

Когда Ρ€Π΅Ρ‡ΡŒ Π·Π°Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΎ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… тСстах, ΠΏΠ΅Ρ€Π²ΠΎΠ΅, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ Π² Π³ΠΎΠ»ΠΎΠ²Ρƒ β€” это Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ Π²Ρ€ΠΎΠ΄Π΅ Shot, Paparazzi, Screengrab ΠΈΠ»ΠΈ Facebook Screenshot Tests. Они каТутся ΠΈΠ΄Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ: Π΄Π΅Π»Π°ΡŽΡ‚ снимки экранов ΠΈ ΡΡ€Π°Π²Π½ΠΈΠ²Π°ΡŽΡ‚ ΠΈΡ… с эталоном. ΠŸΡ€ΠΎΡΡ‚Π°Ρ идСя β€” ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΎΡ…Π²Π°Ρ‚.

Но Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ Ρƒ Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° Π΅ΡΡ‚ΡŒ свои минусы:

  1. Π₯Ρ€ΡƒΠΏΠΊΠΎΡΡ‚ΡŒ. Π”Π°ΠΆΠ΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΡ€Π°Π²ΠΊΠΈ Π² UI (ΡˆΡ€ΠΈΡ„Ρ‚, Ρ†Π²Π΅Ρ‚, Ρ‚Π΅Π½ΡŒ, отступ) Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ падСния тСстов. Π­Ρ‚ΠΈ измСнСния Π½Π΅ всСгда ΠΊΡ€ΠΈΡ‚ΠΈΡ‡Π½Ρ‹ β€” Π½ΠΎ Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ обновлСния эталонных снимков.
  2. Π‘Π»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ CI-ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ. Для ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π½ΡƒΠΆΠ΅Π½ ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³, часто эмулируСмый ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ΠΌ. НапримСр, Paparazzi Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π² JVM, Π½ΠΎ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ настройки Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°. А Shot β€” запускаСтся Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ устройствС, Ρ‡Ρ‚ΠΎ услоТняСт ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ Π² CI.
  3. ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΠΈ. Один экран Π² Ρ€Π°Π·Π½Ρ‹Ρ… состояниях β€” это ΡƒΠΆΠ΅ дСсятки ΡΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ΠΎΠ². А Ссли Π²Ρ‹ добавляСтС Ρ‚Π΅ΠΌΡƒ, язык, ΠΎΡ€ΠΈΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ β€” ΠΈΡ… становится сотни.

ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, состояниС прилоТСния, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для тСста, ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ слоТно воспроизводимым: зарСгистрированный ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ с Π½ΡƒΠΆΠ½ΠΎΠΉ Π²Π΅Ρ€ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠ΅ΠΉ, срСдствами Π½Π° счётС, доступом ΠΊ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΌ инструмСнтам ΠΈΠ»ΠΈ Ρ€Π΅Π³ΠΈΠΎΠ½Π°ΠΌ.

Если это ΡƒΠΆΠ΅ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΎ Π² ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Ρ… UI-тСстах, Π΄ΡƒΠ±Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Ρƒ ΠΆΠ΅ бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ ΠΈ Π² ΡΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚-тСстах – ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π΄ΠΎΡ€ΠΎΠ³ΠΎ ΠΈ нСцСлСсообразно.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π² нашСм случаС ΠΌΡ‹ пошли ΠΏΠΎ ΠΏΡƒΡ‚ΠΈ лСгковСсной ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Ρ… Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… элСмСнтов β€” ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ β€” прямо Π² UI-тСстах, ΡƒΠΆΠ΅ встроСнных Π² ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½.

Π§Ρ‚ΠΎ ΠΌΡ‹ провСряСм?

Π’ΠΎΡ‚ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ кСйс: Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅. Как ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΎ:

  1. ΠŸΠΎΠ΄Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΎΡΡŒ.
  2. ΠžΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅Ρ‚ΡΡ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ.
  3. НС искаТСно (Π½Π΅ растянуто, Π½Π΅ ΠΎΠ±Ρ€Π΅Π·Π°Π½ΠΎ)?

Kakao ΠΈ hasDrawable

Π’ Kakao Π΅ΡΡ‚ΡŒ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΌΠ°Ρ‚Ρ‡Π΅Ρ€ β€” KImageView.hasDrawable(). Π’Ρ‹ просто ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚Π΅ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡ‹ΠΉ drawable, ΠΈ ΠΎΠ½ сравниваСтся с Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΌ. ΠŸΡ€ΠΈ нСобходимости ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ toBitmap() β€” Ρ‚ΠΎΠ³Π΄Π° ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°ΡŽΡ‚ΡΡ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΡΠΎΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ сторон ΠΈΠ»ΠΈ ΠΏΠ»ΠΎΡ‚Π½ΠΎΡΡ‚ΡŒ пиксСлСй.

Но Ρƒ Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° Π΅ΡΡ‚ΡŒ Π΄Π²Π° Π²Π°ΠΆΠ½Ρ‹Ρ… ограничСния:

  1. Drawable Π½Π΅ Ρ€Π°Π²Π΅Π½ отрисованному ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΡŽ ΠœΠ΅Ρ‚ΠΎΠ΄ сравниваСт ImageView.getDrawable() β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π°Π·Π½Π°Ρ‡Π΅Π½ для отобраТСния. Но это Π½Π΅ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΎΠ½ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ отрисовался Π½Π° экранС ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ. Если ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π΅Π·Π°Π½ΠΎ, Π½Π΅ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΎΡΡŒ ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π΅ΠΊΡ€Ρ‹Ρ‚ΠΎ Ρ‡Π΅ΠΌ-Ρ‚ΠΎ Π΄Ρ€ΡƒΠ³ΠΈΠΌ β€” тСст всё Ρ€Π°Π²Π½ΠΎ ΠΏΡ€ΠΎΠΉΠ΄Ρ‘Ρ‚.
  2. Π‘Ρ€Π°Π²Π½Π΅Π½ΠΈΠ΅ пиксСль-Π²-пиксСль β€” слишком строгоС Для сравнСния ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Bitmap.sameAs(). Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΠΎΠΉ идСнтичности ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ β€” Π²ΠΏΠ»ΠΎΡ‚ΡŒ Π΄ΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ пиксСля. Π”Π°ΠΆΠ΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ искаТСния, Π²Ρ‹Π·Π²Π°Π½Π½Ρ‹Π΅ сТатиСм, ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΠΈΠ»ΠΈ нСсовпадСниСм плотности β€” ΠΏΡ€ΠΈΠ²Π΅Π΄ΡƒΡ‚ ΠΊ ΠΏΡ€ΠΎΠ²Π°Π»Ρƒ тСста, Π΄Π°ΠΆΠ΅ Ссли различия Π½Π΅Π·Π°ΠΌΠ΅Ρ‚Π½Ρ‹ Π³Π»Π°Π·Ρƒ.
Π₯ΠΎΡ€ΠΎΡˆΠΎ Ρ€Π°Π·Π±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ Π² Kotlin? Π“ΠΎΡ‚ΠΎΠ²Ρ‹ ΠΏΠΎ ΠΏΠΎΠ»ΠΎΡ‡ΠΊΠ°ΠΌ Ρ€Π°Π·Π»ΠΎΠΆΠΈΡ‚ΡŒ, Ρ‡Π΅ΠΌ ΠΎΠ½ отличаСтся ΠΎΡ‚ Java? ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ свои знания Π² нашСм тСстС. 22 вопроса, Π½ΠΈΠΊΠ°ΠΊΠΈΡ… ΡƒΠ»ΠΎΠ²ΠΎΠΊ.

Как ΠΈΠΌΠ΅Π½Π½ΠΎ ΡΡ€Π°Π²Π½ΠΈΠ²Π°ΡŽΡ‚ΡΡ изобраТСния?

МоТно Π±Ρ‹Π»ΠΎ Π±Ρ‹ Π²Π·ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π³ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ ΠΈΠ· ΠΌΠΈΡ€Π° ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π½ΠΎΠ³ΠΎ зрСния ΠΈ Π½Π° этом этапС. НапримСр:

  1. Core.absdiff ΠΈΠ· OpenCV β€” считаСт Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΡƒΡŽ Ρ€Π°Π·Π½ΠΈΡ†Ρƒ ΠΌΠ΅ΠΆΠ΄Ρƒ двумя изобраТСниями пиксСль Π·Π° пиксСлСм.
  2. ΠœΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ Ρ‚ΠΈΠΏΠ° SSIM (Structural Similarity Index) β€” ΠΎΡ†Π΅Π½ΠΈΠ²Π°ΡŽΡ‚ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ сходство ΠΏΠΎ структурС, контрасту ΠΈ яркости.
  3. Perceptual hash (pHash) β€” Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Ρ…ΡΡˆ, ΠΎΡ‚Ρ€Π°ΠΆΠ°ΡŽΡ‰ΠΈΠΉ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ содСрТаниС, ΠΈ сравниваСт ΠΈΡ….

Но Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ Ρƒ Ρ‚Π°ΠΊΠΈΡ… Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΉ Π΅ΡΡ‚ΡŒ свои Β«Π½ΠΎΒ»:

  1. OpenCV β€” ΠΌΠΎΡ‰Π½Ρ‹ΠΉ, Π½ΠΎ тяТёлый ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²Π°Ρ‚ΡŒ с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ, особСнно Π² Android-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ….
  2. SSIM/pHash β€” слишком ΡƒΠΌΠ½Ρ‹ для простой Π·Π°Π΄Π°Ρ‡ΠΈ: ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ β€œΠΏΡ€ΠΎΡΡ‚ΠΈΡ‚ΡŒβ€ искаТСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π±Ρ‹ Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ».
  3. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Ρ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ врСмя сборки ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΡΠ»ΠΎΠΆΠ½ΠΈΡ‚ΡŒ CI.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΌΡ‹ Π²Ρ‹Π±Ρ€Π°Π»ΠΈ Π±ΠΎΠ»Π΅Π΅ простой ΠΈ прСдсказуСмый ΠΏΡƒΡ‚ΡŒ β€” Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ.

ΠœΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ нСсколько шагов

  • Π“Ρ€Π°Π΄Π°Ρ†ΠΈΠΈ сСрого:

ΠŸΡ€ΠΈΠ²ΠΎΠ΄ΠΈΠΌ ΠΎΠ±Π° изобраТСния ΠΊ ΠΎΠ΄Π½ΠΎΠΌΡƒ Ρ†Π²Π΅Ρ‚ΠΎΠ²ΠΎΠΌΡƒ пространству, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ±Ρ€Π°Ρ‚ΡŒ влияниС Ρ†Π²Π΅Ρ‚Π°, ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ ΡˆΡƒΠΌ ΠΈ ΡΡ€Π°Π²Π½ΠΈΠ²Π°Ρ‚ΡŒ ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ„ΠΎΡ€ΠΌΡƒ ΠΈ содСрТаниС изобраТСния, Π° Π½Π΅ Π΅Π³ΠΎ Ρ†Π²Π΅Ρ‚ΠΎΠ²Ρ‹Π΅ Π½ΡŽΠ°Π½ΡΡ‹.

private fun toGrayscale(bmpOriginal: Bitmap): Bitmap {
    val height = bmpOriginal.height
    val width = bmpOriginal.width
    val bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
    val paint = Paint()
    val cm = ColorMatrix().apply { setSaturation(0f) }
    paint.colorFilter = ColorMatrixColorFilter(cm)
    Canvas(bmpGrayscale).drawBitmap(bmpOriginal, 0f, 0f, paint)
    return bmpGrayscale
}
  • ΠŸΡ€ΠΈΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΊ ΠΌΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€Π΅:

УмСньшаСм ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ³Π»Π°Π΄ΠΈΡ‚ΡŒ ΠΌΠ΅Π»ΠΊΠΈΠ΅ отличия ΠΈ ΡƒΡΠΊΠΎΡ€ΠΈΡ‚ΡŒ сравнСниС, сохранив ΠΏΡ€ΠΈ этом ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ структуру.

bmp1 = ThumbnailUtils.extractThumbnail(bmp1, SAMPLE_SIZE, SAMPLE_SIZE)
  • Расчёт расстояния Π₯эмминга:

РасстояниС Π₯эмминга ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, насколько ΠΎΡ‚Π»ΠΈΡ‡Π°ΡŽΡ‚ΡΡ Π΄Π²Π° изобраТСния ΠΏΠΎ пиксСлям: ΠΎΠ½ΠΎ считаСт количСство нСсовпадСний. Π­Ρ‚ΠΎ простой способ ΠΎΡ†Π΅Π½ΠΈΡ‚ΡŒ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ сходство послС ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ.

private fun calcHammingDistance(a: IntArray, b: IntArray): Int {
    var sum = 0
    for (i in a.indices) {
        sum += if (a[i] == b[i]) 0 else 1
    }
    return sum
}
  • ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° с ΠΏΠΎΡ€ΠΎΠ³ΠΎΠΌ:

Π‘Ρ€Π°Π²Π½ΠΈΠ²Π°Π΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ΅ расстояниС с допустимым ΠΏΠΎΡ€ΠΎΠ³ΠΎΠΌ: Ссли Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΉ мСньшС, Ρ‡Π΅ΠΌ ΠΏΠΎΡ€ΠΎΠ³, считаСм изобраТСния ΠΏΠΎΡ…ΠΎΠΆΠΈΠΌΠΈ. Π­Ρ‚ΠΎ позволяСт ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ отличия, Π²Ρ€ΠΎΠ΄Π΅ ΡˆΡƒΠΌΠ° ΠΈΠ»ΠΈ сглаТивания.

fun assertImageSimilar(bitmap1: Bitmap, bitmap2: Bitmap, threshold: Double) {
    val similarity = calcSimilarity(bitmap1, bitmap2)
    assert(similarity > threshold) {
        "Images too different! Expected β‰₯ $threshold, actual: $similarity"
    }
}

ΠŸΠΎΡ€ΠΎΠ³ подбираСтся эмпиричСски: для ΠΈΠΊΠΎΠ½ΠΎΠΊ β€” строго (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, 0.96), для Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… Ρ„ΠΎΡ‚ΠΎ ΠΈΠ»ΠΈ ΠΎΡ‚Ρ€Π΅Π½Π΄Π΅Ρ€Π΅Π½Π½Ρ‹Ρ… Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ β€” мягчС.

А Ссли Ρ…ΠΎΡ‚ΠΈΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ Π½Π΅ drawable, Π° вСсь View?

МоТно Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒ View Π² Bitmap:

val bitmap = view.drawToBitmap()

И ΡΡ€Π°Π²Π½ΠΈΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ с Π·Π°Ρ€Π°Π½Π΅Π΅ сохранённым эталоном. Π­Ρ‚ΠΎ особСнно ΠΏΠΎΠ»Π΅Π·Π½ΠΎ для кастомных ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈ слоТных Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ.

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΉ (Lottie)

Π‘ Lottie всё слоТнСС. JSON ΡΡ€Π°Π²Π½ΠΈΠ²Π°Ρ‚ΡŒ бСсполСзно β€” нас интСрСсуСт Π½Π΅ структура, Π° Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΎΠ½ΠΎ выглядит. ΠŸΡ€ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ Lottie-Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΡΠ²ΠΈΡ‚ΡŒΡΡ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Ρ‹. Π‘Π°ΠΌΠ° ΠΆΠ΅ вьюшка ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠ±Ρ€Π΅Π·Π°Ρ‚ΡŒΡΡ ΠΈΠ»ΠΈ Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ. ИмСнно поэтому Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½Π°Ρ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° становится критичСски Π²Π°ΠΆΠ½ΠΎΠΉ.

Π’Π°ΠΊ ΠΊΠ°ΠΊ анимация β€” это сСрия ΠΊΠ°Π΄Ρ€ΠΎΠ². ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡ… ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ ΠΏΡƒΡ‚Π΅ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π΅Π΅ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… ΡΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΡ….

Π§Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅ΠΌ:

  • ΠžΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΡŽ Π½Π° Π½ΡƒΠΆΠ½ΠΎΠΌ ΠΊΠ°Π΄Ρ€Π΅:
fun BaseActions.setAnimationFrame(frame: Int) {
    view.perform(object : ViewAction {
        override fun perform(uic: UiController, view: View) {
            val lottieView = view as LottieAnimationView
            lottieView.pauseAnimation()
            lottieView.frame = frame
        }
    })
}
  1. Π‘Ρ€Π°Π²Π½ΠΈΠ²Π°Π΅ΠΌ LottieAnimationView ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ View с сохранённым эталоном Ρ‡Π΅Ρ€Π΅Π· ΡƒΠΆΠ΅ Π·Π½Π°ΠΊΠΎΠΌΡ‹ΠΉ Π½Π°ΠΌ assertImageSimilar.

Как ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ эталоны?

Для сохранСния эталонов ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΎΠ±Ρ…ΠΎΠ΄ Π½ΡƒΠΆΠ½Ρ‹Ρ… View, Ρ‡Ρ‚ΠΎ ΠΈ Π² тСстах, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ вмСсто ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° с assert ΠΏΠΎΠ΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ сохраняСт изобраТСния Π² Ρ„Π°ΠΉΠ».

Π’Π°ΠΊ, ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ Π²Π΅Ρ€ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Π² ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΡΡ‚ΡŒ отобраТСния, ΠΌΡ‹ сохраняСм эталонныС изобраТСния β€” ΠΈ дальшС ΡƒΠΆΠ΅ автоматичСский тСст сравниваСт с Π½ΠΈΠΌΠΈ, ΡƒΠ±Π΅ΠΆΠ΄Π°ΡΡΡŒ, Ρ‡Ρ‚ΠΎ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ измСнилось.

Π˜Ρ‚ΠΎΠ³

Π€Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ Π²Ρ€ΠΎΠ΄Π΅ Espresso ΠΈ Kaspresso β€” Π³ΠΈΠ±ΠΊΠΈΠ΅ ΠΈ ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ Ρ€Π°ΡΡˆΠΈΡ€ΡΡŽΡ‚ΡΡ. НС Π±ΠΎΠΉΡ‚Π΅ΡΡŒ ΠΏΠΈΡΠ°Ρ‚ΡŒ свои ΠΌΠ°Ρ‚Ρ‡Π΅Ρ€Ρ‹: Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ усилий β€” ΠΈ Ρƒ вас ΡƒΠΆΠ΅ Π½Π΅ ΠΊΠΎΡΡ‚Ρ‹Π»ΡŒ, Π° ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ инструмСнт, идСально подходящий ΠΏΠΎΠ΄ ваш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚.

ΠœΡ‹ Π½Π°ΡƒΡ‡ΠΈΠ»ΠΈ ΠΌΠ°ΡˆΠΈΠ½Ρƒ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ Ρ€Π°Π·Π½ΠΈΡ†Ρƒ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ°ΠΌΠΈ: Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ сравнСниС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ с допуском, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Lottie-ΠΊΠ°Π΄Ρ€ΠΎΠ² ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ эталоны. И всё это встроили Π² ΠΏΡ€ΠΈΠ²Ρ‹Ρ‡Π½Ρ‹Π΅ UI-тСсты: ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· Π³Π»Π°Π·Π°ΠΌΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠ»ΠΈ β€” дальшС ΠΏΡƒΡΡ‚ΡŒ страдаСт автотСст.

πŸ“± Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° мобильного Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° мобильного Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°Β»

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

admin
10 фСвраля 2019

Python + Visual Studio Code = ΡƒΡΠΏΠ΅ΡˆΠ½Π°Ρ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°

БупСрсСт Python ΠΈ Visual Studio Code Π² дСйствии! ПолноС руководство ΠΏΠΎ наст...
admin
24 сСнтября 2017

6 сСрвисов для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π±Π»ΠΎΠΊ-схСмами

Π—Π°Ρ‡Π°ΡΡ‚ΡƒΡŽ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π»ΡƒΡ‡ΡˆΠ΅ ΠΏΠΎΠ½ΡΡ‚ΡŒ Π·Π°Π΄Π°Ρ‡Ρƒ ΠΈ быстрСС Π΅Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Ρ€Π°...
Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста
06 фСвраля 2017

15 прСкрасных ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² для Sublime Text

ВстрСчайтС список ΠΏΠ΅Ρ€Π²ΠΎΠΉ нСобходимости – 15 самых Π½ΡƒΠΆΠ½Ρ‹Ρ… ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² для Subli...