forked from barryclark/jekyll-now
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
249 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
--- | ||
layout: post | ||
title: Testing ứng dụng của bạn trong Xcode phần 1 Unit test | ||
categories: ios developer | ||
--- | ||
Ứng dụng hoặc bất kì sản phẩm nào trước khi đến tay người dùng, đều phải trải qua 1 quá trình test cẩn thận. Khi nói về test nhiều người sẽ nghĩ người tester sẽ ngồi hàng giờ kiểm tra từng màn hình, từng nút bấm để phát hiện ra điều bất thường và báo lại cho nhà phát triển,thường một ứng dụng lớn thì đội tester sẽ mất rất nhiều thời gian để kiểm thử từng chức năng, thậm chí sau đó dev có thể thay đổi code và sau đó tất cả các việc test của tester sẽ phải bắt đầu lại khá mất thời gian | ||
Vì lý do đấy nhiều công ty đang bắt đầu viết automation test cho project của họ, hình ảnh phía giới biểu thị các loại test | ||
![](https://docs-assets.developer.apple.com/published/20b3426c34/93cc7b80-dd57-423d-be85-f937da693ec3.png) | ||
|
||
Tính từ giới kim tự tháp đầu tiên là Unit test, sau đó đến Integration Test và cuối cùng là UI test | ||
|
||
## Unit testing là gì ? | ||
Unit test là một trong những khái niệm căn bản nhẩt của automation test, là phương pháp kiểm tra tính đúng đắn của một đoạn mã nguồn | ||
## Integration test | ||
Tương tự như Unit test điều khác biệt ở đây là nó có thể cover rộng hợn so với Unit test, đối với Unit test thì nó chỉ cover được một phạm vi logic rất nhỏ của app, còn Integration test có thể cover được chức năng của một hệ thống nhỏ kết hợp giữa class và function | ||
|
||
## UI test | ||
Là bước cuối cùng của automation test ,UI test chạy lậu nhất so với hai thằng còn lại, nó có khả năng gi lại những tương tác của user lên giao diện và chuyển nó thành mã nguồn | ||
|
||
## Performance Testing | ||
<img src="https://i.imgur.com/h2qJt9L.png" width=50% /> | ||
|
||
Unit test chạy nhanh nhất <br/> | ||
Tiếp đến interaction test <br/> | ||
UI test tốc độ chạy chậm nhất | ||
|
||
Trong bài viết này chúng ta sẽ tìm hiểu ở bước căn bản nhất của testing đó chính là Unit test | ||
|
||
## Lợi ích của Unit test | ||
Unittest hữu ích khi làm việc với codebase lớn, khi dự án phải làm việc với nhiều dev khác tiết kiệm thời gian thay đổi chỉnh sửa chức năng mà không sợ ảnh hưởng đến code của ông khác hạn chế bug phát sinh, mình đã từng đau khổ khi maintain các dự án cũ nhưng không có unittest kết quả là sửa tính năng này, thì lại hỏng tính năng kia vì các tính năng đều liên quan đến nhau nên code có unittest thì s | ||
|
||
## Thực hành | ||
### Bước 1 Tạo project | ||
<img src="https://i.imgur.com/Zz0zQHF.png" width=50% /> | ||
|
||
Chúng ta tích vào include Unit test và UI test như mình mô tả | ||
|
||
### Bước 2 Chúng ta sẽ có 2 thư mục UI test và Unit test | ||
<img src="https://i.imgur.com/twfc7Jd.png" width=50% /> | ||
|
||
Chúng ta sẽ tiến hành viết code test cho từng phương thức test trong 2 thư mục này | ||
|
||
Một unit test sẽ test 1 case cụ thể, và trong một phương thức thường sẽ có 4 bước | ||
1 Setup | ||
</br> | ||
Khởi tạo classs mà bạn muốn test | ||
</br> | ||
2 Execution | ||
</br> | ||
Gọi những phương thức ở trong class | ||
</br> | ||
3 Expection | ||
</br> | ||
Kiểm kết quả mong đợi của kết quả trả về | ||
4 Clean up | ||
|
||
|
||
Chúng ta có test case đơn giản như sau </br> | ||
Case 1 Người dùng đăng nhập tài trạng thái active | ||
</br> | ||
Setup:Tạo một function phương thức đăng nhập user | ||
</br> | ||
Execution:chạy function | ||
</br> | ||
Expection: trả về True | ||
</br> | ||
|
||
Case 2 Người dùng đăng nhập tài trạng thái inactive | ||
|
||
Setup:Tạo một function phương thức đăng nhập user | ||
</br> | ||
Execution:chạy function | ||
</br> | ||
Expection: trả về False | ||
</br> | ||
|
||
|
||
Bây giờ chúng ta sẽ chuyển đoạn mã giả trên thành code nào, đầu tiên khi tạo project chúng ta sẽ tích vào Unit test nhé | ||
|
||
``` Swift | ||
enum UserStatus:Int { | ||
case active = 1 | ||
case inactive = 2 | ||
} | ||
|
||
enum BiometricType:Int { | ||
case figgerPrint = 0 | ||
case faceId = 1 | ||
case enterText = 2 | ||
case wrongPass = 3 | ||
} | ||
|
||
enum LoginStaus:Int { | ||
case scucess = 0 | ||
case failure = 1 | ||
} | ||
|
||
func performGetStatusUser(userStatus: UserStatus, biometric: BiometricType) -> LoginStaus { | ||
if userStatus == .active { | ||
switch biometric { | ||
case .figgerPrint: | ||
return .scucess | ||
case .faceId: | ||
return .scucess | ||
case .enterText: | ||
return .scucess | ||
case .wrongPass: | ||
return .failure | ||
} | ||
} else { | ||
|
||
return .failure | ||
} | ||
} | ||
``` | ||
Bây giờ chúng ta sẽ viết test cho function trên chúng ta tạo một class kế thừa từ thằng [XCTestCase]("https://developer.apple.com/documentation/xctest/xctestcase") | ||
nó chứa các test function cho class và function | ||
|
||
``` Swift | ||
|
||
import XCTest | ||
@testable import Binance // import tên project chúng ta muống test vào | ||
|
||
class BinanceTests: XCTestCase { | ||
public var viewHome = HomeViewModel() | ||
|
||
override func setUp() { | ||
super.setUp() | ||
viewHome.binding(delegate: self) // khởi tạo class mà chúng ta muốn test | ||
|
||
} | ||
|
||
override func tearDown() { | ||
super.tearDown() | ||
viewHome.unbinding(delegate: self) | ||
} | ||
|
||
func test_UserStatus () { | ||
let userStatus = viewHome.interactor.performGetStatusUser(userStatus:.active, biometric: .faceId) == .scucess | ||
XCTAssertTrue(userStatus, "valid") | ||
} | ||
|
||
``` | ||
|
||
**Setup** là phương thức khởi tạo các phương thức test | ||
</br> | ||
**TearDown** là phương thức clean sau mỗi phương thức hoàn thành test case nó thực thi theo cơ chế LIFO | ||
|
||
Để chạy được test case chúng ta có thể dùng tổ hợp phím Comand + Shift+ U để chạy toàn bộ test case or chúng ta có thể bấm vào test case mà chúng ta muốn chạy | ||
|
||
Với test case đầu tiền kết quả mà chúng ta mong đợi là True | ||
<br> | ||
<img src="https://i.imgur.com/Q7nZ9KV.png" width=40% /> | ||
<br> | ||
|
||
Với test case thứ 2 kết quả mà chúng ta mong đợi là False | ||
<br> | ||
<img src="https://i.imgur.com/sCVURKf.png" width=40% /> | ||
<br> | ||
|
||
Chúng ta có một class Helper như này, nhiệm vụ của chúng ta là viết test case để xem cái function **stringToDate** này có sau khị truyền 2 tham số là date dạng string và kiểu format thì có convert được về date hay không | ||
|
||
``` Swift | ||
|
||
import Foundation | ||
|
||
class AppHelper { | ||
|
||
static let shareInstance = AppHelper() | ||
|
||
func stringToDate(dateStr:String,format:String) ->Date? { | ||
let dateFormatterGet = DateFormatter() | ||
dateFormatterGet.dateFormat = format | ||
|
||
guard let dateResult = dateFormatterGet.date(from: dateStr) else { return nil} | ||
|
||
return dateResult | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
``` | ||
Chúng ta sẽ test function stringToDate này chúng ta sẽ có Test case như sau | ||
</br> | ||
Case 1 Dữ liệu truyền vào đúng format | ||
</br> | ||
Setup:Tạo một function truyền kiểu date dạng string vào và format mong muốn | ||
Execution:chạy function | ||
</br> | ||
Expection: trả về khác nil | ||
</br> | ||
|
||
Case 2 Dữ liệu truyền vào đúng format | ||
|
||
Setup:Tạo một function phương thức đăng nhập user | ||
</br> | ||
Execution:chạy function | ||
</br> | ||
Expection: trả về bằng nil | ||
</br> | ||
Bây giờ chúng ta sẽ viết code để chuyển đoạn mã giã trên thành code | ||
|
||
|
||
``` Swift | ||
|
||
import XCTest | ||
@testable import Binance | ||
class HelperTest: XCTestCase { | ||
|
||
var sut:AppHelper! | ||
|
||
override func setUp() { | ||
super.setUp() | ||
sut = AppHelper() | ||
} | ||
override func tearDown() { | ||
sut = nil | ||
super.tearDown() | ||
|
||
|
||
} | ||
|
||
func test_formatDate() { | ||
let isValidDateFormat = sut.stringToDate(dateStr: "10/10/2021", format: "dd/MM/yyyy") | ||
XCTAssertNil(isValidDateFormat) | ||
|
||
} | ||
|
||
|
||
``` | ||
|
||
Kết quả của test case đầu tiên là | ||
<br> | ||
<img src="https://i.imgur.com/GYYOpKr.png" width=40% /> | ||
<br> | ||
|
||
Kết quả test case thứ 2 là : | ||
<br> | ||
<img src="https://i.imgur.com/KDafLvt.png" width=40% /> | ||
<br> | ||
|
||
## Kết luận | ||
Bài viết này mình đã giới thiệu cho các bạn những khái niệm căn bản nhất của Unit test, và chúng ta cũng ta cũng đã thử viết 1 unit test căn bản, hy vọng bài viết của mình sẽ hữu ích cho bạn khi mới tiếp cận đến unit test, trong bài viết sắp tới mình sẽ chia sẻ cho các bạn về UI test, mọi ý kiến đóng góp mong các bạn gửi về địa chỉ sphamtrungkiendev@gmail.com hoặc bình luận phía giới của bài viết này nhé! | ||
|
||
Bài viết tham khảo của | ||
[Apple document](https://developer.apple.com/documentation/xcode/testing-your-apps-in-xcode) | ||
|