July 19, 2015

Automatic UI Testing ด้วย Xcode 7

Xcode 7 มาพร้อมกับ Automatic UI Testing ที่จะช่วยให้เราสามารถทดสอบ UI ได้ง่ายมากขึ้นกว่าวิธีเดิมๆ มาก ซึ่งจุดเด่นของ Automatic UI Testing ที่มาพร้อมกับ Xcode 7 ก็คือ
  1. ไม่จำเป็นต้องเขียน script ทดสอบเองทั้งหมด เพราะมีระบบบันทึก (UI Recording) การใช้งาน และสร้างโค้ดออกมาให้เราเองอัตโนมัติ สิ่งที่เราต้องทำเพิ่มก็คือ เขียนและออกแบบเงื่อนไข ต่างๆ ที่เราต้องการทดสอบ
  2. เข้าถึง UI Element ต่างๆ บนหน้าจอด้วยการอ้างถึง element นั้นๆ จริงๆ ไม่ใช่การกำหนดพิกัด หรืออ้างตำแหน่งของการแตะ หรือการ swipe ซึ่งการระบุพิกัดมีข้อเสียมากๆ ก็คือ หากแอปเราทำงานบนหน้าจอหลากหลายขนาด วิธีการนี้อาจใช้งานไม่ได้เลย ยิ่งถ้าแอปเรามีการเคลื่อนย้าย UI Element บนหน้าจอในขณะใช้งานด้วยแล้วล่ะก็ยิ่งแย่ไปใหญ่ ซึ่งการอ้างถึง UI Element ต่างๆ บนหน้าจอนั้น Xcode 7 จะใช้ความสามารถของ Accessibility ที่มีมาบน iOS ก่อนหน้านี้นานแล้ว (แต่นักพัฒนาหลายท่านไม่ค่อยใช้กัน -- รวมทั้งผมเองด้วย)
  3. รัน Test ไปพร้อมๆ กับ การรัน Unit Test ตามปกติ ไม่ต้องแยกแอปออกมาต่างหาก เหมือนกับการทำ UI Test แบบเดิมๆ ที่ต้องรัน Instrument ขึ้นมา ซึ่งวุ่นวาย และช้าอืดอาด ... ใช่แล้ว ตอนนี้ Automatic UI Testing ผนวกเข้าเป็นหนึ่งเดียวกับ Xcode 7 เลย!
  4. ใช้ XCTest Framework ที่คุ้นเคย


ตัวอย่างที่ใช้ในบทความนี้ เป็นแอปที่มีคุณลักษณะดังนี้

หน้าแรก
  • มีปุ่ม Switch ที่เมื่อมีสถานะเป็น off แล้ว ปุ่ม Show Detail จะไม่สามารถกดได้
  • เมื่อกดปุ่ม View Detail แล้วจะ Push หน้าจอ Detail เข้ามา

หน้าจอ Detail
  • เมื่อกดปุ่ม Increase Number แล้วตัวเลขด้านล่างจะเพิ่มขึ้นทีละ 1

* ตอนสร้างโปรเจ็คใหม่ด้วย Xcode 7 จะมีตัวเลือก Include UI Tests เพิ่มเข้ามาด้วย

UI Recording
ก่อนที่เราจะเริ่ม Record เราต้องวางแผนให้เรียบร้อยก่อน ว่าจะทดสอบอะไรบ้าง โดยการทดสอบสิ่งต่างๆ บนหน้าจอว่าค่าที่ได้ตรงตามต้องการหรือไม่ ซึ่งเราจะทำผ่าน XCTest Framework ซึ่งมี API เข้ามาใหม่ 3 อัน ดังนี้
  1. XCUIApplication - เป็นตัวแทนของแอปที่กำลังถูกทดสอบ 
  2. XCUIElement - เป็นตัวแทนของ UI element ต่างๆ ของแอปที่ถูกทดสอบ โดย element แต่ละอันก็จะมีชนิด และ identifier ของตัวเอง เพื่อช่วยให้เราค้นหาและเจาะจงหา UI Element ที่เราต้องการบนหน้าจอได้ 
  3. XCUIElementQuery - เราจะใช้ก็ต่อเมื่อเราต้องการหา UI Element บนหน้าจอ
สำหรับการใช้งาน Accessibility นั้น เราสามารถกำหนด identifier, label หรือค่าอื่นๆ ให้กับ UI Element ที่ต้องการได้ ไม่ว่าจะกำหนดจากโค้ด หรือกำหนดผ่าน Xcode Inspector แนะนำให้อ่านรายละเอียด Accessibility Programming Guide for iOS

Test 1
ถ้า switch ปิดอยู่ แล้วกดปุ่ม Show Detail จะไม่เกิดอะไรขึ้น

เริ่มจากให้สร้างฟังก์ชันในไฟล์ UITest.swift ที่ Xcode สร้างมาให้ตอนสร้างโปรเจ็ค



ให้ click ที่บรรทัดที่ 2 ด้านในฟังก์ชัน เพื่อกำหนดจุดว่าจะให้ Xcode 7 สร้างโค้ดบันทึกการใช้งานตรงนี้นะ จากนั้นกดปุ่มสีแดง ด้านล่าง เพื่อบันทึก แอปจะเปิดตัวขึ้นมา ให้เรากด switch ไป 1 ที ปุ่มจะ disable และให้กดที่ ปุ่ม Show Detail ไปอีก 1 ที และกดปุ่มสีแดงปุ่มเดิม เพื่อหยุดการ Record เราก็จะได้โค้ดออกมาประมาณนี้


จากโค้ด อธิบายได้ว่า เราอ้างถึง switch ด้วยชื่อ "Toggle Show Detail Switch" จากนั้นสั่งกดไป 1 ครั้ง เพื่อให้ swich เป็น off และเราก็กดปุ่ม Show Detail โดยอ้างถึงปุ่มจากชื่อ "Show Detail" และจากนั้นให้เราใช้ XCTAssertEqual เพื่อตรวจสอบว่าเรายังอยู่หน้าเดิมใช่หรือไม่ ก็จะได้โค้ดเต็มๆ ออกมาแบบนี้


จากโค้ด เราใช้วิธีดูว่า title bar ยังเป็นหน้าเดิมอยู่ไหม ซึ่งทำแบบนี้อาจไม่ใช่ทางเลือกที่ดีนักในทุกๆ กรณี แต่สำหรับตัวอย่างนี้แบบนี้ก็ถือว่าเพียงพอแล้ว

Test 2
ถ้า switch เปิดอยู่แล้ว กดปุ่ม Show Detail แอปจะแสดงหน้า Detail

ให้ทำแบบเดียวกับ Test 1 แต่ต่างกันตรงที่ เปิดแอปขึ้นมาแล้ว ให้เรากดปุ่ม Show Detail เลย โดยไม่ต้องปิด switch ก่อน และทดสอบว่า title bar เป็นคำว่า Detail หรือยัง เราก็จะได้โค้ดมาแบบนี้


Test 3
กดปุ่ม increment button ในหน้า detail แล้วตัวเลขเพิ่มขึ้นทีละ 1

ทำคล้ายกับขั้นตอนที่สอง คือเปิดแอปขึ้นมา กดปุ่ม Detail และกดปุ่ม Increse Number จากนั้นกดหยุด แต่โค้ดที่ได้ ก็คือการกดปุ่ม Increase Number ครั้งเดียว หากเราต้องการทดสอบการกดไปเรื่อยๆ มากกว่า 1 ครั้ง ให้แก้ไขโค้ดให้เป็นแบบนี้


จากโค้ดจะพบว่า แต่ละรอบในการกดปุ่ม ให้ใส่ XCTAssertEqual เพื่อตรวจสอบค่าใน UILabel

UI Test ทั้ง 3 อันอาจยังดูไม่ครอบคลุมทุกกรณีนัก เช่น ยังขาดการตรวจสอบว่า ถ้า switch เป็น off แล้ว ปุ่ม Show Detail ควร disable หรือตรวจสอบว่า เมื่อกดปุ่ม Back กลับมาแล้ว หน้าจอแรกควรเป็นอย่างไร เป็นต้น แต่ก็ถือว่าเป็นจุดเริ่มต้นที่ดีสำหรับใครที่ยังไม่คุ้นเคย

เกี่ยวกับ Accessibility
จากโค้ดตัวอย่าง พบว่าเราอ้างถึงชื่อของ element ต่างๆ แล้วชื่อเหล่านั้น เราจะรู้ได้อย่างไรล่ะ? สำหรับคนที่เคยใช้ Accessibility คงจะไม่สงสัยอะไร แต่ถ้าใครยังไม่รู้นั้น จริงๆ แล้ว ทุก UI Element นั้นเราสามารถกำหนด ID, Hint, Label หรือ Trait ให้ หรือแม้แต่กำหนดว่าจะอนุญาตให้ Accessibility เข้าถึง element นั้นได้หรือไม่ผ่าน Inspector ใน Xcode ดังรูป


เนื่องจากเราพึ่งพา Accessibility ดังนั้น value ที่ใช้ตรวจสอบใน Test 3 เราก็ต้องกำหนดค่าให้ Accessibility เองเช่นกัน ดังนี้


ถ้า Test Fail ล่ะ?
ให้เปิด Xcode's Report Navigator ขึ้นมา (กด command+8) เพื่อดูได้ว่า Test ไหนบ้างที่ไม่ผ่าน อีกทั้งแต่ละขั้นตอน ยังมีรูปลูกตาไว้ท้ายชื่อ เมื่อกดแล้วจะมี screenshot ให้ดูอีกด้วย


ทำไมเราถึงต้องทำ UI Testing?
เพิ่มการรับประกันคุณภาพของ Software และเพื่อให้เรามีความมั่นใจก่อนจะ release แอปมากขึ้น และที่สำคัญไปกว่านั้น Accessibility ไม่เพียงแต่เข้ามาช่วยเราทำ Automatic UI Testing เท่านั้น แต่ยังช่วยให้คนที่มีความบกพร่องทางร่างกาย (เช่นคนตาบอด) เข้าถึงและใช้งานแอปเราได้สะดวกมากขึ้นอีกด้วย

อ่านต่อ