สิ่งที่สำคัญที่สุดอย่างหนึ่งที่คุณสามารถทำได้ในฐานะผู้ทดสอบเพื่อให้งานของคุณมีประสิทธิภาพและรวดเร็วยิ่งขึ้นคือการทำให้แอปที่คุณกำลังทดสอบเป็นแบบอัตโนมัติ การใช้การทดสอบด้วยตนเองเพียงอย่างเดียวนั้นเป็นไปไม่ได้เนื่องจากคุณจะต้องเรียกใช้การทดสอบแบบเต็มทุกวันบางครั้งหลายครั้งต่อวันการทดสอบการเปลี่ยนแปลงทุกครั้งที่ส่งไปยังโค้ดของแอป
บทความนี้จะอธิบายเส้นทางของทีมในการระบุตัวตน EarlGrey 1.0 ของ Google เป็นเครื่องมือที่ทำงานได้ดีที่สุดสำหรับเราในบริบทของการทำงานอัตโนมัติของ iOS แอพ ApeeScape Talent . การที่เราใช้มันไม่ได้หมายความว่า EarlGrey เป็นเครื่องมือทดสอบที่ดีที่สุดสำหรับทุกคน แต่เป็นเครื่องมือที่เหมาะกับความต้องการของเรา
ในช่วงหลายปีที่ผ่านมาทีมของเราได้สร้างแอพมือถือที่แตกต่างกันทั้งบน iOS และ Android ในตอนแรกเราพิจารณาใช้เครื่องมือทดสอบ UI ข้ามแพลตฟอร์มที่จะช่วยให้เราเขียนชุดการทดสอบชุดเดียวและดำเนินการได้ในระบบปฏิบัติการมือถือที่แตกต่างกัน อันดับแรกเราไปด้วย แอปเปิล ซึ่งเป็นตัวเลือกโอเพนซอร์สที่ได้รับความนิยมสูงสุด
แต่เมื่อเวลาผ่านไป ข้อ จำกัด ของ appium ชัดเจนมากขึ้นเรื่อย ๆ ในกรณีของเราข้อบกพร่องหลักสองประการของ Appium คือ:
เพื่อลดข้อบกพร่องแรกของ Appium เราได้เขียนการปรับแต่งโค้ดและแฮ็กทุกประเภทเพื่อให้การทดสอบมีเสถียรภาพมากขึ้น อย่างไรก็ตามไม่มีอะไรที่เราสามารถทำได้เพื่อจัดการกับเหตุการณ์ที่สอง ทุกครั้งที่มีการเปิดตัว iOS หรือ Android เวอร์ชันใหม่ Appium ใช้เวลานานในการติดตาม และบ่อยครั้งเนื่องจากมีบั๊กจำนวนมากการอัปเดตครั้งแรกจึงไม่สามารถใช้งานได้ ด้วยเหตุนี้เรามักถูกบังคับให้ดำเนินการทดสอบบนแพลตฟอร์มเวอร์ชันเก่าหรือปิดการทดสอบทั้งหมดจนกว่าจะมีการอัปเดต Appium ที่ใช้งานได้
แนวทางนี้ยังห่างไกลจากอุดมคติและเนื่องจากปัญหาเหล่านี้รวมถึงประเด็นอื่น ๆ ที่เราจะไม่กล่าวถึงในรายละเอียดเราจึงตัดสินใจมองหาทางเลือกอื่น เกณฑ์ยอดนิยมสำหรับเครื่องมือทดสอบใหม่คือ เพิ่มเสถียรภาพ และ อัปเดตเร็วขึ้น . หลังจากการตรวจสอบเราตัดสินใจใช้เครื่องมือทดสอบเนทีฟสำหรับแต่ละแพลตฟอร์ม
ดังนั้นเราจึงเปลี่ยนเป็น แสดงออก สำหรับโครงการ Android และ EarlGrey 1.0 สำหรับ การพัฒนา iOS . ในการมองย้อนกลับไปตอนนี้เราสามารถพูดได้ว่านี่เป็นการตัดสินใจที่ดี เวลาที่“ เสียไป” เนื่องจากความจำเป็นในการเขียนและดูแลชุดการทดสอบที่แตกต่างกันสองชุดสำหรับแต่ละแพลตฟอร์มนั้นมีมากกว่าการสร้างขึ้นโดยไม่จำเป็นต้องตรวจสอบการทดสอบที่ไม่สม่ำเสมอจำนวนมากและไม่มีการหยุดทำงานของการอัปเดตเวอร์ชัน
คุณจะต้องรวมเฟรมเวิร์กไว้ในโปรเจ็กต์ Xcode เดียวกันกับแอพที่คุณกำลังพัฒนา ดังนั้นเราจึงสร้างโฟลเดอร์ในไดเรกทอรีรากเพื่อโฮสต์การทดสอบ UI การสร้าง EarlGrey.swift
ไฟล์เป็นสิ่งจำเป็นเมื่อติดตั้งกรอบการทดสอบและเนื้อหาถูกกำหนดไว้ล่วงหน้า
EarlGreyBase
เป็นคลาสหลักสำหรับคลาสทดสอบทั้งหมด มันมี setUp
ทั่วไป และ tearDown
วิธีการขยายจาก XCTestCase
. ใน setUp
เราโหลดต้นขั้วที่มักจะใช้โดยการทดสอบส่วนใหญ่ (เพิ่มเติมเกี่ยวกับการตัดต่อในภายหลัง) และเรายังตั้งค่าสถานะการกำหนดค่าบางอย่างที่เราสังเกตเห็นว่าช่วยเพิ่มความเสถียรของการทดสอบ:
// Turn off EarlGrey's network requests tracking since we don't use it and it can block tests execution GREYConfiguration.sharedInstance().setValue(['.*'], forConfigKey: kGREYConfigKeyURLBlacklistRegex) GREYConfiguration.sharedInstance().setValue(false, forConfigKey: kGREYConfigKeyAnalyticsEnabled)
เราใช้รูปแบบการออกแบบ Page Object - แต่ละหน้าจอในแอปมีคลาสที่สอดคล้องกันซึ่งมีการกำหนดองค์ประกอบ UI ทั้งหมดและการโต้ตอบที่เป็นไปได้ ชั้นเรียนนี้เรียกว่า 'เพจ' วิธีการทดสอบถูกจัดกลุ่มตามคุณสมบัติที่อยู่ในไฟล์และคลาสที่แยกจากกันจากเพจ
วิธีใช้เทอร์มินัลบลูมเบิร์ก
เพื่อให้คุณมีความคิดที่ดีขึ้นว่าทุกอย่างจะแสดงอย่างไรนี่คือลักษณะของหน้าจอการเข้าสู่ระบบและลืมรหัสผ่านในแอปของเราและลักษณะที่แสดงโดยวัตถุของหน้า
ต่อไปในบทความนี้เราจะนำเสนอเนื้อหารหัสของออบเจ็กต์หน้าเข้าสู่ระบบ
วิธีที่ EarlGrey ซิงโครไนซ์การดำเนินการทดสอบกับแอปไม่ได้สมบูรณ์แบบเสมอไป ตัวอย่างเช่นอาจพยายามคลิกปุ่มที่ยังไม่ได้โหลดในลำดับชั้นของ UI ทำให้การทดสอบล้มเหลว เพื่อหลีกเลี่ยงปัญหานี้เราได้สร้างวิธีการที่กำหนดเองเพื่อรอจนกว่าองค์ประกอบต่างๆจะปรากฏในสถานะที่ต้องการก่อนที่เราจะโต้ตอบ
นี่คือตัวอย่างบางส่วน:
static func asyncWaitForVisibility(on element: GREYInteraction) { // By default, EarlGrey blocks test execution while // the app is animating or doing anything in the background. //https://github.com/google/EarlGrey/blob/master/docs/api.md#synchronization GREYConfiguration.sharedInstance().setValue(false, forConfigKey: kGREYConfigKeySynchronizationEnabled) element.assert(grey_sufficientlyVisible()) GREYConfiguration.sharedInstance().setValue(true, forConfigKey: kGREYConfigKeySynchronizationEnabled) } static func waitElementVisibility(for element: GREYInteraction, timeout: Double = 15.0) -> Bool { GREYCondition(name: 'Wait for element to appear', block: { var error: NSError? element.assert(grey_notNil(), error: &error) return error == nil }).wait(withTimeout: timeout, pollInterval: 0.5) if !elementVisible(element) { XCTFail('Element didn't appear') } return true }
อีกสิ่งหนึ่งที่ EarlGrey ไม่ได้ทำด้วยตัวเองคือการเลื่อนหน้าจอจนกว่าองค์ประกอบที่ต้องการจะปรากฏให้เห็น นี่คือวิธีที่เราสามารถทำได้:
static func elementVisible(_ element: GREYInteraction) -> Bool { var error: NSError? element.assert(grey_notVisible(), error: &error) if error != nil { return true } else { return false } } static func scrollUntilElementVisible(_ scrollDirection: GREYDirection, _ speed: String, _ searchedElement: GREYInteraction, _ actionElement: GREYInteraction) -> Bool { var swipes = 0 while !elementVisible(searchedElement) && swipes = 10 { return false } else { return true } }
วิธีการยูทิลิตี้อื่น ๆ ที่ขาดหายไปจาก API ของ EarlGrey ที่เราระบุคือการนับองค์ประกอบและการอ่านค่าข้อความ รหัสสำหรับยูทิลิตี้เหล่านี้มีอยู่ใน GitHub: ที่นี่ และ ที่นี่ .
เพื่อให้แน่ใจว่าเราหลีกเลี่ยงผลการทดสอบที่ผิดพลาดที่เกิดจากปัญหาเซิร์ฟเวอร์ส่วนหลังเราใช้ไฟล์ OHHTTPS ห้องสมุด เพื่อจำลองการเรียกเซิร์ฟเวอร์ เอกสารในหน้าแรกของพวกเขาค่อนข้างตรงไปตรงมา แต่เราจะนำเสนอวิธีที่เราหยุดการตอบสนองในแอปของเราซึ่งใช้ GraphQL API
class StubsHelper { static let testURL = URL(string: 'https://[our backend server]')! static func setupOHTTPStub(for request: StubbedRequest, delayed: Bool = false) { stub(condition: isHost(testURL.host!) && hasJsonBody(request.bodyDict())) { _ in let fix = appFixture(forRequest: request) if delayed { return fix.requestTime(0.1, responseTime: 7.0) } else { return fix } } } static let stubbedEmail = ' [email protected] ' static let stubbedPassword = 'password' enum StubbedRequest { case login func bodyDict() -> [String: Any] { switch self { case .login: return EmailPasswordSignInMutation( email: stubbedTalentLogin, password: stubbedTalentPassword ).makeBodyIdentifier() } } func statusCode() -> Int32 { return 200 } func jsonFileName() -> String { let fileName: String switch self { case .login: fileName = 'login' } return '(fileName).json' } } private extension GraphQLOperation { func makeBodyIdentifier() -> [String: Any] { let body: GraphQLMap = [ 'query': queryDocument, 'variables': variables, 'operationName': operationName ] // Normalize values like enums here, otherwise body comparison will fail guard let normalizedBody = body.jsonValue as? [String: Any] else { fatalError() } return normalizedBody } }
การโหลดต้นขั้วทำได้โดยการเรียก setupOHTTPStub
วิธี:
StubsHelper.setupOHTTPStub(for: .login)
ส่วนนี้จะแสดงให้เห็นว่าเราใช้หลักการทั้งหมดที่อธิบายไว้ข้างต้นเพื่อเขียนการทดสอบการเข้าสู่ระบบแบบ end-to-end จริงได้อย่างไร
import EarlGrey final class LoginPage { func login() -> HomePage { fillLoginForm() loginButton().perform(grey_tap()) return HomePage() } func fillLoginForm() { ElementsHelper.waitElementVisibility(emailField()) emailField().perform(grey_replaceText(StubsHelper.stubbedTalentLogin)) passwordField().perform(grey_tap()) passwordField().perform(grey_replaceText(StubsHelper.stubbedTalentPassword)) } func clearAllInputs() { if ElementsHelper.elementVisible(passwordField()) { passwordField().perform(grey_tap()) passwordField().perform(grey_replaceText('')) } emailField().perform(grey_tap()) emailField().perform(grey_replaceText('')) } } private extension LoginPage { func emailField(file: StaticString = #file, line: UInt = #line) -> GREYInteraction { return EarlGrey.selectElement(with: grey_accessibilityLabel('Email'), file: file, line: line) } func passwordField(file: StaticString = #file, line: UInt = #line) -> GREYInteraction { return EarlGrey.selectElement( with: grey_allOf([ grey_accessibilityLabel('Password'), grey_sufficientlyVisible(), grey_userInteractionEnabled() ]), file: file, line: line ) } func loginButton(file: StaticString = #file, line: UInt = #line) -> GREYInteraction { return EarlGrey.selectElement(with: grey_accessibilityID('login_button'), file: file, line: line) } } class BBucketTests: EarlGreyBase { func testLogin() { StubsHelper.setupOHTTPStub(for: .login) LoginPage().clearAllInputs() let homePage = LoginPage().login() GREYAssertTrue( homePage.assertVisible(), reason: 'Home screen not displayed after successful login' ) } }
เราใช้ Jenkins เป็นระบบการผสานรวมอย่างต่อเนื่องของเราและเราเรียกใช้การทดสอบ UI สำหรับแต่ละข้อตกลงในคำขอดึงทุกครั้ง
ความจริงที่ว่าเงินสดที่ลงทุนได้รับรายได้เมื่อเวลาผ่านไปเรียกว่ามูลค่าเงินตามเวลา
เราใช้ fastlane scan
เพื่อดำเนินการทดสอบใน CI และสร้างรายงาน การมีภาพหน้าจอแนบมากับรายงานเหล่านี้เพื่อการทดสอบที่ล้มเหลวจะมีประโยชน์ น่าเสียดาย scan
ไม่มีฟังก์ชันนี้ดังนั้นเราจึงต้องกำหนดเอง
ใน tearDown()
เราตรวจพบว่าการทดสอบล้มเหลวและบันทึกภาพหน้าจอของโปรแกรมจำลอง iOS หากเป็นเช่นนั้น
import EarlGrey import XCTest import UIScreenCapture override func tearDown() { if testRun!.failureCount > 0 { // name is a property of the XCTest instance // https://developer.apple.com/documentation/xctest/xctest/1500990-name takeScreenshotAndSave(as: name) } super.tearDown() } func takeScreenshotAndSave(as testCaseName: String) { let imageData = UIScreenCapture.takeSnapshotGetJPEG() let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) let filePath = '(paths[0])/(testCaseName).jpg' do { try imageData?.write(to: URL.init(fileURLWithPath: filePath)) } catch { XCTFail('Screenshot not written.') } }
ภาพหน้าจอจะถูกบันทึกไว้ในโฟลเดอร์ Simulator และคุณจะต้องดึงภาพจากที่นั่นเพื่อที่จะแนบเป็นสิ่งประดิษฐ์ในการสร้าง เราใช้ Rake
เพื่อจัดการสคริปต์ CI ของเรา นี่คือวิธีที่เรารวบรวมสิ่งประดิษฐ์การทดสอบ:
def gather_test_artifacts(booted_sim_id, destination_folder) app_container_on_sim = `xcrun simctl get_app_container #{booted_sim_id} [your bundle id] data`.strip FileUtils.cp_r '#{app_container_on_sim}/Documents', destination_folder end
หากคุณกำลังมองหาวิธีที่รวดเร็วและเชื่อถือได้ในการทำให้ไฟล์ ios การทดสอบอย่ามองไปไกลกว่า EarlGrey ได้รับการพัฒนาและดูแลโดย Google (ฉันต้องพูดมากกว่านี้หรือไม่) และในหลาย ๆ ประการมันเหนือกว่าเครื่องมืออื่น ๆ ที่มีอยู่ในปัจจุบัน
คุณจะต้องคนจรจัดเล็กน้อยกับกรอบเพื่อเตรียมวิธีการยูทิลิตี้เพื่อส่งเสริมเสถียรภาพในการทดสอบ ในการดำเนินการนี้คุณสามารถเริ่มต้นด้วยตัวอย่างวิธีการยูทิลิตี้ที่กำหนดเองของเรา
เราขอแนะนำให้ทดสอบกับข้อมูลที่ถูกดึงออกเพื่อให้แน่ใจว่าการทดสอบของคุณจะไม่ล้มเหลวเนื่องจากเซิร์ฟเวอร์ส่วนหลังไม่มีข้อมูลการทดสอบทั้งหมดที่คุณคาดว่าจะมี ใช้ OHHTTPStubs
หรือเว็บเซิร์ฟเวอร์ท้องถิ่นที่คล้ายกันเพื่อให้งานสำเร็จลุล่วง
เมื่อเรียกใช้การทดสอบใน CI ตรวจสอบให้แน่ใจว่าได้จัดเตรียมภาพหน้าจอสำหรับกรณีที่ล้มเหลวเพื่อให้การดีบักง่ายขึ้น
คุณอาจสงสัยว่าทำไมเราถึงยังไม่ย้ายไปที่ EarlGrey 2.0 และนี่คือคำอธิบายโดยย่อ เวอร์ชันใหม่เปิดตัวเมื่อปีที่แล้วและสัญญาว่าจะมีการปรับปรุงบางอย่างในเวอร์ชัน 1.0 โชคดีที่เมื่อเรานำ EarlGrey มาใช้ v2.0 นั้นไม่เสถียรเป็นพิเศษ ดังนั้นเราจึงยังไม่ได้เปลี่ยนไปใช้เวอร์ชัน 2.0 อย่างไรก็ตามทีมงานของเรากำลังรอการแก้ไขข้อบกพร่องสำหรับเวอร์ชันใหม่อย่างใจจดใจจ่อเพื่อให้เราสามารถย้ายโครงสร้างพื้นฐานของเราได้ในอนาคต
ตลาดที่สามารถระบุตำแหน่งได้คืออะไร
คู่มือการเริ่มต้นใช้งาน EarlGrey เกี่ยวกับ หน้าแรกของ GitHub คือ ที่ สถานที่ที่คุณต้องการเริ่มต้นหากคุณกำลังพิจารณากรอบการทดสอบสำหรับโครงการของคุณ คุณจะพบคู่มือการติดตั้งที่ใช้งานง่ายเอกสาร API ของเครื่องมือและข้อมูลสรุปที่มีประโยชน์ซึ่งแสดงวิธีการทั้งหมดของเฟรมเวิร์กในลักษณะที่ใช้ง่ายในขณะเขียนการทดสอบของคุณ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเขียนการทดสอบอัตโนมัติสำหรับ iOS คุณสามารถดูหนึ่งใน บล็อกโพสต์ก่อนหน้านี้ของเรา .
การทดสอบการทำงานเป็นกระบวนการตรวจสอบการทำงานของระบบ ดังนั้นการทดสอบ UI จึงเป็นการทดสอบการทำงานผ่านอินเทอร์เฟซผู้ใช้
การทดสอบ UI จะตรวจสอบว่าแอปพลิเคชันหลายชั้นทำงานร่วมกันตามที่ควรหรือไม่ การทดสอบระดับล่างเช่นการทดสอบหน่วยหรือการทดสอบ API ไม่สามารถใช้เครือข่ายขนาดใหญ่เพื่อค้นหาจุดบกพร่องได้เช่นเดียวกับการทดสอบ UI
มีเครื่องมือเฉพาะที่คุณสามารถใช้ได้ทั้งนี้ขึ้นอยู่กับลักษณะของระบบที่คุณต้องการทดสอบ เครื่องมือทดสอบ UI อัตโนมัติที่รู้จักกันดี ได้แก่ Selenium, Appium, Ranorex หรือ AutoIt