Tìm hiểu Unit Testing trên iOS
Khi mới làm quen với việc lập trình, thông thường các lập trình viên không chú ý nhiều tới các phương pháp test code của mình. Họ thường code các module, rồi chạy thử chương trình, break, debug,... để tìm và fix bug trong code. Tuy nhiên, việc test thủ công này trong nhiều trường hợp có thể mất rất ...
Khi mới làm quen với việc lập trình, thông thường các lập trình viên không chú ý nhiều tới các phương pháp test code của mình. Họ thường code các module, rồi chạy thử chương trình, break, debug,... để tìm và fix bug trong code. Tuy nhiên, việc test thủ công này trong nhiều trường hợp có thể mất rất nhiều thời gian để test. Hơn nữa, trong một số trường hợp, các module của chương trình quá phức tạp khiến cho lập trình viên rất khó khăn trong việc tìm bug, thậm chí là không tìm ra bug.
Vì vậy, việc áp dụng phương pháp test trong khi code trở thành một phần quan trọng trong quá trình code. Trong các phương pháp test, Unit testing được nhắc tới và sử dụng rộng rãi nhất. Unit testing là một phương pháp test mà các lập trình viên sẽ chia nhỏ việc test ra thành các unit nhỏ, test từng module, method của chương trình.
Unit testing mang lại rất nhiều lợi ích cho lập trình viên. Bằng việc test từng unit của chương trình, lập trình viên có thể chắc chắn những unit code đã được test của họ chắc chắn không có bug. Hơn nữa, để sử dụng hiệu quả unit testing, lập trình viên phải viết code thành các module, không để code của cả chương trình quá rắc rối, chồng chéo, phức tạp.
Trên Xcode 7, Apple hỗ trợ rất tốt chúng ta sử dụng unit testing. Trên Xcode, chúng ta được tích hợp sẵn các Framework, API,... và cả test tool để chúng ta test từng module mà không cần phải chạy cả project.
Sau đây, tôi xin tạo một project demo đơn giản sử dụng unit testing để chúng ta cùng tìm hiểu cách sử dụng unit testing trong project.
1. Tạo project
Chúng ta mở Xcode, tạo new project -> iOS Application -> Single view application, chọn ngôn ngữ là swift, lưu ý tích chọn vào ô include Unit Tests và tạo project.
Project demo rất đơn giản. Chúng ta sẽ chỉ có 1 view controller với 2 ô text field để users điền vào 2 số, và 1 button để khi users bấm vào, chúng ta sẽ tính toán và hiển thị kết quả của phép nhân 2 số vừa nhập vào label bên dưới.
Đầu tiên, mở file storyboard và kéo vào view controller các elements như trong hình sau:
Mục tiêu của bài viết này là tìm hiểu về unit testing, vì vậy chúng ta sẽ không quan tâm nhiều đến giao diện. Các bạn có thể chỉnh lại giao diện, thêm màu mè tùy thích.
Tiếp theo, chúng ta mở assistant editor và kéo các outlet, action chúng ta vừa tạo từ storyboard vào view controller:
- firstNumTextField, secondNumTextField outlet cho 2 text field
- resultLabel outlet cho label hiển thị kết quả
- onButtonClicked action cho action khi button được bấm
Tiếp theo chúng ta implement button action, và thêm các hàm như sau:
@IBAction func onButtonClicked(sender: AnyObject) { let number1 = firstNumTextField.text! let number2 = secondNumTextField.text! if number1.characters.count == 0 || number2.characters.count == 0 { return } let result = multiply(Double(number1)!, num2: Double(number2)!) showResult("(result)") } func multiply(num1: Double, num2: Double) -> Double { return (num1 * num2 / 2) } func showResult(result: String) { resultLabel.text = result + "123" }
Vậy là chúng ta đã hoàn thành việc code cho project, bây giờ chúng ta sẽ chuyển sang phần tiếp theo: Unit testing
2. Unit testing
Hãy để ý phần project navigator trên Xcode, ngoài các file của project, Xcode còn tạo cho chúng ta target UnitTestingTutorialTests với file UnitTestingTutorialTests.swift. Mở file UnitTestingTutorialTests.swift, các bạn có thể thấy class UnitTestingTutorialTests thừa kế từ XCTestCase class; trong class UnitTestingTutorialTests đã được viết sẵn 4 hàm setUp(), tearDown(), testExample() và testPerformanceExample():
- setUp(): Được gọi trước khi thực thi các hàm test
- tearDown(): Được gọi sau khi các hàm test được thực thi
- testExample() và testPerformanceExample(): 2 hàm example của Xcode
Hãy để ý 2 hàm testExample() và testPerformanceExample(), các bạn có thể thấy ở đầu của 2 hàm này có 2 ô hình thoi. Các ô này có thể click vào, và chúng chính là những ô để chúng ta test. Chúng ta hãy thử click vào 1 ô, các bạn sẽ thấy Xcode bắt đầu build, và sau đó sẽ có biểu tượng build successed, kèm theo đó là ô chúng ta vừa click vào sẽ chuyển sang màu xanh.
Ta đa, vậy là các bạn vừa thực hiện việc build unit test trên hàm example của Xcode, bây giờ chúng ta sẽ tự tạo unit test của chúng ta.
Đầu tiên, khai báo property viewController trong class UnitTestingTutorialTests:
var viewController: ViewController!
Sau đó, trong hàm setUp(), gán giá trị cho viewController
override func setUp() { super.setUp() let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()) viewController = storyboard.instantiateInitialViewController() as! ViewController }
Bây giờ chúng ta sẽ tạo hàm cho unit test. Vẫn trong UnitTestingTutorialTests, chúng ta thêm function sau:
func testMultiplyFunction() { }
Hãy để ý hàm chúng ta vừa tạo, để có thể thực hiện unit test, hàm chúng ta tạo ra cần phải bắt đầu với tiền tố test
Các bạn hãy xem lại file ViewController.swift, bây giờ chúng ta sẽ implement hàm testMultiplyFunction() để test hàm multiply() của class này:
func testMultiplyFunction() { let multi = viewController.multiply(12, num2: 10) XCTAssert(multi == 120) }
Ở đây, chúng ta tạo một biến multi với giá trị là kết quả trả về của hàm multiply() của instance viewcontroller chúng ta khởi tạo bên trên.
Hãy để ý hàm XCTAssert(), hàm này nhận giá trị đầu vào kiểu Bool, kết quả của việc test phụ thuộc vào giá trị chúng ta truyền vào hàm này. Khi chúng ta truyền vào giá trị true, hàm test của chúng ta trả về success và ngược lại, failed với giá trị false được truyền vào.
Cụ thể trong trường hợp này, chúng ta muốn test xem kết quả của hàm multiply() có chính xác hay không, nên chúng ta đã truyền vào hàm này 2 số 12 và 10. Chúng ta đều biết 12 nhân 10 phải ra 120 là chính xác, nên theo suy đoán của chúng ta, giá trị của multi phải là 120. Chính vì vậy, chúng ta truyền giá trị Bool "multi == 120" vào hàm XCTAssert(). Khi chúng ta chạy hàm test này, kết quả ô hình thoi ở đầu hàm testMultiplyFunction() chuyển màu xanh và Xcode thông báo "test success" có nghĩa là hàm multiply() của chúng ta là chính xác.
OK, test thôi, bấm vào ô hình thoi ở đầu hàm testMultiplyFunction() nào. Oops,... kết quả ra "test failed", và ô này chuyển sang màu đỏ.
Vậy là hàm multiply() của chúng ta đã có lỗi, chúng ta cùng xem lại nào. Hiện tại hàm multiply của chúng ta đang là thế này:
func multiply(num1: Double, num2: Double) -> Double { return (num1 * num2 / 2) }
Ngó qua cũng thấy hàm viết sai, nhân 2 số mà lại đi chia cho 2 nữa làm gì, học sinh cấp 1 cũng thấy chỗ sai. Tất nhiên là hàm này phải viết sai thì mới có cái mà nói, chứ viết đúng thì chúng ta đã không có lỗi để mà nói =))
Chúng ta cùng sửa lại hàm cho đúng và test lại thôi nào:
func multiply(num1: Double, num2: Double) -> Double { return num1 * num2 }
Kết quả:
Great, vậy là chúng ta đã hoàn thành unit testing cho hàm multiply(), giờ chúng ta có thể chắc chắn hàm này là đúng, nếu code của chúng ta lỗi thì hàm này không liên can