Slide 1

Slide 1 text

SCREENSHOT TESTING NIKOS LINAKIS - CHRISTOFOROS FILIPPOU ANDROID TEAM @XM TESTING THE UI AND BEYOND

Slide 2

Slide 2 text

TESTING • Unit tests for business logic • UI tests for business or presentation logic • Robolectric for asserting view state • Espresso for interactions, layout

Slide 3

Slide 3 text

VISUAL TESTING METHOD SCREENSHOT TESTING

Slide 4

Slide 4 text

Diff Verify Record COMPARING SCREENSHOTS SCREENSHOT TESTING

Slide 5

Slide 5 text

WHY DO THIS? SCREENSHOT TESTING • They assert more properties than a unit test normally does

Slide 6

Slide 6 text

SCREENSHOT TESTING EVERYTHING THE LIGHT TOUCHES IS OUR… TEST!

Slide 7

Slide 7 text

WHY DO THIS? SCREENSHOT TESTING • They assert more properties than a unit test normally does • A fast way to see how our view looks while developing • Immediately detect UI breaking changes and avoid regression bugs

Slide 8

Slide 8 text

MULTIPLE UI CASES SCREENSHOT TESTING

Slide 9

Slide 9 text

TESTING LANGUAGES SCREENSHOT TESTING

Slide 10

Slide 10 text

TESTING DEVICES SIZES SCREENSHOT TESTING

Slide 11

Slide 11 text

TESTING THEMES SCREENSHOT TESTING

Slide 12

Slide 12 text

SCREENSHOT TESTING

Slide 13

Slide 13 text

SCREENSHOT TESTING

Slide 14

Slide 14 text

+ KARUMI/SHOT GRADLE PLUGIN SCREENSHOT-TESTS-FOR-ANDROID • Developed and used by Facebook • Html report (visual diff of failed tests) • CI friendly

Slide 15

Slide 15 text

FIRST TEST import org.junit.Test class MyFirstTest { @Test @Throws(Throwable::class) fun testRendering() { } }

Slide 16

Slide 16 text

FIRST TEST import org.junit.Test class MyFirstTest { @Test @Throws(Throwable::class) fun testRendering() { val targetContext = getInstrumentation().targetContext val inflater = LayoutInflater.from(targetContext) val view = inflater.inflate(R.layout.market_hours_view, null, false) } }

Slide 17

Slide 17 text

FIRST TEST import org.junit.Test class MyFirstTest { @Test @Throws(Throwable::class) fun testRendering() { val targetContext = getInstrumentation().targetContext val inflater = LayoutInflater.from(targetContext) val view = inflater.inflate(R.layout.market_hours_view, null, false) ViewHelpers.setupView(view).setExactWidthDp(300).layout() } }

Slide 18

Slide 18 text

FIRST TEST import org.junit.Test class MyFirstTest { @Test @Throws(Throwable::class) fun testRendering() { val targetContext = getInstrumentation().targetContext val inflater = LayoutInflater.from(targetContext) val view = inflater.inflate(R.layout.market_hours_view, null, false) ViewHelpers.setupView(view).setExactWidthDp(300).layout() } }

Slide 19

Slide 19 text

FIRST TEST import org.junit.Test class MyFirstTest { @Test @Throws(Throwable::class) fun testRendering() { val targetContext = getInstrumentation().targetContext val inflater = LayoutInflater.from(targetContext) val view = inflater.inflate(R.layout.market_hours_view, null, false) ViewHelpers.setupView(view).setExactWidthDp(300).layout() } }

Slide 20

Slide 20 text

FIRST TEST import org.junit.Test class MyFirstTest { @Test @Throws(Throwable::class) fun testRendering() { val targetContext = getInstrumentation().targetContext val inflater = LayoutInflater.from(targetContext) val view = inflater.inflate(R.layout.market_hours_view, null, false) ViewHelpers.setupView(view).setExactWidthDp(300).layout() Screenshot.snap(view).record() } }

Slide 21

Slide 21 text

DEMO

Slide 22

Slide 22 text

THE PERFECT PULL REQUEST

Slide 23

Slide 23 text

MEDIUM BLOG POST https://medium.com/xmglobal

Slide 24

Slide 24 text

REFERENCES • https://speakerdeck.com/linakis/screenshot-testing-for-android • https://medium.com/xmtrading/screenshot-testing-101-7dd24ca6b8ce • https://github.com/trading-point/screenshot-testing-android-demo • https://youtu.be/tpHsAx8HSkU • https://facebook.github.io/screenshot-tests-for-android/ • https://github.com/Karumi/Shot

Slide 25

Slide 25 text

THANK YOU QUESTIONS?