May 24, 2016

Monkey Test in iOS Project ให้ลิงลองเล่นแอพเราดูหน่อยซิ

มีคนกล่าวไว้ว่าการทดสอบซอฟท์แวร์ควรเป็นกิจกรรมที่เราต้องทำเป็นปกติตลอดเวลาที่เราพัฒนาซอฟท์แวร์ ซึ่งการทดสอบก็มีหลายระดับตั้งแต่ระดับฟังก์ชันการใช้งาน, UI หรือระดับโค้ดที่เขียนขึ้นมา อย่างน้อยก็เพื่อให้มั่นใจว่าซอฟแวร์ของเราไม่พังกลางทาง และทำงานได้ถูกต้องนั่นเอง

มีการทดสอบแบบหนึ่ง ที่ไม่ได้มีจุดประสงค์หลักในการทดสอบเชิงฟังก์ชัน แต่เน้นไปที่การดูว่าถ้าซอฟท์แวร์เราถูกใช้ไปนานๆ หรือใช้ในรูปแบบแปลกๆ ไม่เจาะจง จะทำให้แอพพังหรือไม่ นั่นก็คือการทดสอบที่เราเรียกมันว่า Stress Test

ปกติการทดสอบแบบนี้เรามักใช้คนมากดแอพเรามั่วๆ กดอะไรก็ได้เรื่อยๆ กดไปนานๆ เผื่อเจอจุดผิดในแอพ กดไปเลยนานๆ เล่นไปเลยเรื่อยๆ เผื่อแอพจะพังเข้าสักวันเพราะสาเหตุอะไรก็ว่าไป การกดแบบไม่คิดและมีรูปแบบมั่วๆ เหล่านี้เรามักเรียกเปรียบว่าเอาแอพให้ลิงลองกดเล่นดู หรือการกดแบบลิง

ในฝั่ง Android นั้นมี ลิง ของตัวเองสำหรับทำ stress test มาให้แล้ว แล้วในฝั่ง iOS ล่ะ ? อันที่จริง Instruments ที่ติดมากับ Xcode นั้นสามมารถทำ stress test ได้ แต่มันไม่ได้ถูกออกแบบมาให้เราใช้งานได้อย่างตรงไปตรงมาสำเร็จรูปแบบเดียวกับที่ Android มีสักทีเดียว

วิธีที่เราจะใช้ทำ stress test กับ iOS แอพของเราก็คือการเขียนโค้ด javascript แล้วสั่งมันสุ่มวนทำ Interaction ต่างๆ บนหน้าจอไปเรื่อยๆ เท่านั้นเอง

สำหรับหลายคน แค่คิดว่าจะต้องเขียน Javascript ก็รู้สึกไม่ค่อยสบายใจแล้ว ทำไมต้องมาหัดเขียน Javascript เพื่อทดสอบอีกล่ะ ? แล้วถ้าเขียนไม่เป็นล่ะจะทำยังไง ?

โชคดีที่โลกนี้ยังไม่สิ้นหวังไปซะทั้งหมด เพราะนาย Jonathan Penn ได้เขียน Javascript ชุดนี้ให้เรานำมาใช้ใน Instruments ได้เลย ... เอาล่ะ มาลองใช้กันสักหน่อยว่าเป็นยังไง


นำสคริปไปใช้

1. เปิด Xcode Project ที่เราต้องการทำ stress test ขึ้นมา จากนั้นกดปุ่ม Command + I หรือที่เมนูด้านบนให้เลือก Product -> Profile เพื่อรัน Instruments

2. เมื่อ Instruments รันขึ้นมาแล้ว ให้เราเลือกสร้าง Profilling Template ชื่อ Automation แบบนี้


3. ขั้นตอนต่อไปเราจะใช้สคริปที่เราโหลดมา โดยเลือก Script ตรงนี้ตามภาพด้านล่าง และ copy โค้ดในไฟล์ UIAutoMonkey.js มาวางไว้ใน code editor


4. จากนั้นกดปุ่มรันโค้ดตามภาพด้านล่าง ทุกอย่างควรต้องรันได้ตามปกติ ลิงของเราจะสุ่มเล่นแอพเราไปเรื่อยๆ โดยที่ระหว่างลิงเราเล่นแอพอยู่ เราสามารถสลับ panel จาก Script ไปเป็น Editor Log เพื่อดูว่าสคริปมัน generate event อะไรขึ้นมาบ้างก็ได้


หน้าจอตอนที่เรารันสคริปจะแสดง Log ออกมาว่าลิงของเราทำอะไรไปบ้าง

ถ้าทุกอย่างรันได้ตามปกติแล้ว ต่อไปเราก็มาดูกันว่าเราสามารถใช้งานสคริปนี้ยังไงได้บ้าง ให้ลองดูโค้ดบริเวณด้านบนของสคริปที่เรา paste ลงไป จะเห็น configure ประมาณนี้


การตั้งค่าตรงนี้เป็นการกำหนดวิธีการ random event หรือสุ่มเหตุการณ์ ขึ้นมา ว่าควรมีรูปแบบอัตราส่วนของ event ที่จะเกิดเป็นอย่างไร เราสามารถปรับแต่งค่าเหล่านี้ได้ ซึ่งตัวแปรที่เค้าทำมาให้เรากำหนดค่า ก็มีความหมายก็ตรงตัวตามนั้นเลย หรือจะลองอ่านคำอธิบายเพิ่มเติมจากในสคริปอีกก็ได้

หากต้องการกำหนดคำสั่งต่างๆ ให้ลิงของเราทำอะไรบางอย่างเพิ่มเติม เราสามารถสร้าง object ของ UIAutoMonkey ขึ้นมา จากนั้นกำหนดค่าให้กับ attribute และสั่ง ปล่อยลิงให้เล่นแอพของเราต่อได้ เช่น สั่งให้ลิงสุ่มเหตุการณ์ขึ้นมา 1,000 ครั้ง และ capture หน้าจอทุก ๆ 5 วินาที แบบนี้


แต่เดี๋ยวก่อน ถ้า copy โค้ดนี้ไปใช้แล้วกดรันทันทีเราจะยังไม่สามารถรันสคริปได้ ต้องเข้าไปกำหนด path ของไฟล์ต่างๆ ที่เราที่นำมาใช้ก่อนเริ่มตั้งแต่ path ของไฟล์ Includes.js ที่เรา import เข้ามา และ path ของไฟล์ต่างๆ ในไฟล์ Include.js ด้วย หลังจากเรากำหนด path ครบแล้ว ถึงจะรันได้

นอกจากนี้ยังมี Scenario อื่นๆ ที่เราสามารถเล่นกับมันได้ เช่น หากเราไม่ต้องการกำหนดจำนวนครั้งของเหตุการณ์ที่ให้ลิงสุ่มขึ้นมา ก็สามารถกำหนดเป็นเวลาได้ ว่าจะให้ลิงเราเล่นต่อเนื่องกันกี่นาที กี่ชั่วโมง แบบนี้



UI Holes

ตอนที่เราปล่อยให้ลิงของเราเล่นแอพเราอย่างสนุกสนาน อาจมีบางจังหวะที่ลิงเผลอกดเข้าไปยังหน้าจอที่กลับออกมายาก และในหน้าจอนั้นก็ไม่ได้มีนัยยะสำคัญอะไรที่จะให้ลิงกดเล่นต่อไปนานๆ หน้านี้ก็ควรเข้าไปแล้วก็รีบๆ กลับออกมาซะจะได้ไม่เสียเวลา ซึ่งหน้าจอที่กลับออกมายากก็เช่น หน้าจอที่เวลาจะปิดมัน ต้องกดปุ่ม back หรือ กดปุ่ม close เล็กๆ ที่อยู่ตรงมุมจอเล็กๆ ซึ่งถ้าเราจะรอให้ลิงกดเล่นให้โดนปุ่มนั้น อาจเสียเวลารอนานได้ หน้าจอที่เข้าไปแล้ว กลับออกมายาก เราเรียก UI ส่วนนี้ว่า UI Holes

เราสามารถเพิ่มความฉลาดให้ลิงอีกนิด ด้วยการใช้ condition handler โดยกำหนดว่า ทุกๆ กี่เหตุการณ์ให้ทำ event นี้นะ ดังตัวอย่างโค้ดต่อไปนี้เราจะกำหนดให้ทุกๆ 10 เหตุการณ์ให้ลิงพยายามหาปุ่ม Back และปุ่ม Done ซึ่งถ้าหากว่าเจอ ก็ให้กด (ชื่อปุ่มนั้น จะสัมพันธ์กับ accessibility ที่เราตั้งให้) แบบนี้


ส่วน parameter ตอนสร้าง ButtonHandler นั้นเรากำหนดค่าอะไรได้บ้าง ให้ลองเปิดไฟล์ buttonHandler.js ดูเองนะ :)

อีกสถานการณ์หนึ่ง สมมติว่าแอพเราจำเป็นต้องทำอะไรก่อน เช่น login ให้ผ่านก่อน ลิงถึงจะนำไปเล่นล่ะ ต้องทำยังไง ?

ถ้าเราให้ลิงเล่นแอพแต่แรกด้วยการกดมั่วๆ ไปเรื่อย คงไม่มีทาง หรือเป็นไปได้ยากที่จะผ่านหน้า login ไปได้ ดังนั้นก่อนให้มันเล่น เราจำเป็นต้องเขียนสคริปเองก่อน! ... นั่นไง วนกลับมาที่ Javascript อีกแล้ว ถ้าไม่อยากเขียน หรือเขียนไม่เป็นล่ะจะทำยังไง ? ไม่ต้องห่วง Instruments มีฟีเจอร์​ Record and Play มาให้

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


ตอนที่เราสั่ง record โค้ดก็จะถูก generate ขึ้นมาแบบเดียวกับตอนที่เรา record UI ตอนทำ UI Testing ใน Xcode เลย ถ้าดูจากโค้ดก็พอจะอ่านเข้าใจว่า ให้แตะ username textfield จากนั้นพิมพ์คำว่า khomkrit ลงไป เสร็จแล้วก็กดปุ่ม login ง่ายจริงๆ

หากมีบางจังหวะเราอาจรันแล้วไม่มีอะไรเกิดขึ้น ให้เรากลับไปที่ Xcode แล้วกดรัน Instruments ใหม่ (Product -> Profile) จากนั้น ที่หน้าจอ Instruments ให้เราเลือก target ให้ถูกต้องก่อนกดรัน


เพียงเท่านี้เราก็พอจะมีลิงมากดเล่นแอพของเราแล้ว โดยไม่ต้องจ้างให้คนมานั่งกดมั่วๆ อีกต่อไป จะเปิดให้ลิงเราเล่นแอพเราทั้งคืนเป็นสิบๆ ชั่วโมงก็ได้ เอาให้มั่นใจว่าต่อให้เล่นมั่วยังไง แอพเราก็ไม่พังแน่นอนไปเลย

สรุป

เราเขียนสคริปใน Instruments เพื่อทำ Automate UI Testing ได้
มีคนแบ่งปันสคริปชื่อ UI AutoMonkey ให้เราใช้ เราแค่นำมาใช้ใน Instruments และแก้ไขค่า
หากมี Configure หลายแบบ ใน Instruments เราสามารถเซฟเป็นไฟล์เก็บไว้ใช้แยกกันก็ได้
อยากรู้รายละเอียดการเขียนท่าต่างๆ ไปอ่านต่อได้ที่ Automate UI Testing in iOS
ถ้าอยากรู้ว่าเราทำอะไรกับลิงได้บ้าง ให้เปิดอ่านไฟล์ดู และอ่านเพิ่มเติมที่ UI AutoMonkey