1. Trước khi bắt đầu
Trong các lớp học lập trình trước đây, bạn đã tìm hiểu cách sử dụng ViewModel
để xử lý logic kinh doanh, cũng như LiveData
cho giao diện người dùng phản ứng. Trong lớp học lập trình này, bạn sẽ tìm hiểu cách viết mã kiểm thử đơn vị để kiểm tra xem mã ViewModel
của bạn có chạy tốt hay không.
Điều kiện tiên quyết
- Bạn đã tạo thư mục kiểm thử trong Android Studio.
- Bạn đã viết mã kiểm thử đơn vị và kiểm thử đo lường trong Android Studio.
- Bạn đã thêm phần phụ thuộc Gradle vào một dự án Android.
Kiến thức bạn sẽ học được
- Cách viết mã kiểm thử đơn vị cho
ViewModel
vàLiveData
.
Bạn cần có
- Máy tính đã cài đặt Android Studio.
- Mã giải pháp cho ứng dụng Cupcake.
Tải mã khởi động xuống cho lớp học lập trình này
Trong lớp học lập trình này, bạn sẽ thêm các mã kiểm thử đo lường vào ứng dụng Cupcake từ mã giải pháp trước đó.
Để lấy đoạn mã cho lớp học lập trình này và mở đoạn mã đó trong Android Studio, hãy thực hiện các bước sau.
Lấy mã
- Nhấp vào URL được cung cấp. Thao tác này sẽ mở trang GitHub của dự án trong một trình duyệt.
- Kiểm tra để đảm bảo tên nhánh khớp với tên nhánh được chỉ định trong lớp học lập trình. Ví dụ: trong ảnh chụp màn hình sau đây, tên nhánh là chính.
- Trên trang GitHub cho dự án này, nhấp vào nút Mã. Thao tác này sẽ khiến một cửa sổ bật lên.
- Trong cửa sổ bật lên, nhấp vào nút Download ZIP (Tải tệp ZIP xuống) để lưu dự án vào máy tính. Chờ quá trình tải xuống hoàn tất.
- Xác định vị trí của tệp trên máy tính (thường nằm trong thư mục Downloads (Tệp đã tải xuống)).
- Nhấp đúp vào tệp ZIP để giải nén. Thao tác này sẽ tạo một thư mục mới chứa các tệp dự án.
Mở dự án trong Android Studio
- Khởi động Android Studio.
- Trong cửa sổ Welcome to Android Studio (Chào mừng bạn đến với Android Studio), nhấp vào Open (Mở).
Lưu ý: Nếu Android Studio đã mở thì chuyển sang chọn tuỳ chọn File (Tệp) > Open (Mở) trong trình đơn.
- Trong trình duyệt tệp, hãy chuyển đến vị trí của thư mục dự án chưa giải nén (có thể nằm trong thư mục Downloads (Tệp đã tải xuống)).
- Nhấp đúp vào thư mục dự án đó.
- Chờ Android Studio mở dự án.
- Nhấp vào nút Run (Chạy) để tạo bản dựng và chạy ứng dụng. Đảm bảo ứng dụng được xây dựng như mong đợi.
2. Tổng quan về ứng dụng khởi động
Ứng dụng Cupcake có màn hình chính hiện một màn hình đặt hàng với 3 lựa chọn về số lượng cupcake. Khi nhấp vào một tuỳ chọn, bạn sẽ được chuyển đến màn hình để chọn hương vị, rồi tiếp đó chuyển đến màn hình để chọn ngày đến lấy bánh. Sau đó, bạn có thể gửi đơn hàng đến một ứng dụng khác. Bạn có thể huỷ đơn đặt hàng ở bất kỳ giai đoạn nào vừa nêu.
3. Tạo thư mục kiểm thử đơn vị
Tạo thư mục kiểm thử đơn vị cho ứng dụng Cupcake như bạn đã làm trong các lớp học lập trình trước đó.
4. Tạo lớp kiểm thử đơn vị
Tạo một lớp mới với tên gọi ViewModelTests.kt.
5. Thêm các phần phụ thuộc cần thiết
Thêm các phần phụ thuộc sau vào dự án của bạn:
testImplementation 'junit:junit:4.+'
testImplementation 'androidx.arch.core:core-testing:2.1.0'
Bây giờ, hãy đồng bộ hoá dự án của bạn.
6. Viết mã kiểm thử ViewModel
Hãy bắt đầu bằng một mã kiểm thử đơn giản. Việc đầu tiên chúng ta làm khi tương tác với ứng dụng trên một thiết bị hoặc trình mô phỏng là chọn số lượng cupcake. Cho nên, trước hết chúng ta sẽ kiểm thử phương thức setQuantity()
trong OrderViewModel
và kiểm tra giá trị của đối tượng quantity
LiveData
.
Chúng ta sẽ kiểm thử biến quantity
, đó là một thực thể của LiveData
. Việc kiểm thử đối tượng LiveData
cần có thêm một bước và đây chính là nơi phần phụ thuộc được thêm vào phát huy tác dụng. Chúng ta dùng LiveData
để cập nhật giao diện người dùng ngay khi giá trị thay đổi. Giao diện người dùng của chúng ta chạy trên điều chúng ta gọi là "chuỗi chính". Đừng lo nếu bạn không quen với việc tạo chuỗi và tính năng đồng thời, chúng ta sẽ tìm hiểu sâu hơn về vấn đề này trong các lớp học lập trình khác. Đến đây, hãy coi chuỗi chính là chuỗi giao diện người dùng trong ứng dụng Android. Mã hiển thị giao diện người dùng đến người dùng chạy trên chuỗi này. Trừ phi có quy định khác, mã kiểm thử đơn vị giả định rằng mọi thứ đều chạy trên chuỗi chính. Tuy nhiên, vì các đối tượng LiveData
không thể truy cập vào chuỗi chính, nên chúng ta phải tuyên bố rõ rằng các đối tượng LiveData
không được gọi chuỗi chính.
- Để xác định rõ đối tượng
LiveData
không được gọi chuỗi chính, cần cung cấp một quy tắc kiểm thử cụ thể bất cứ khi nào chúng ta kiểm thử một đối tượngLiveData
.
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
- Giờ đây, chúng ta có thể tạo một hàm có tên là
quantity_twelve_cupcakes()
. Trong phương thức này, tạo một thực thể củaOrderViewModel.
- Trong kiểm thử này, bạn sẽ kiểm tra để bảo đảm rằng đối tượng
quantity
trongOrderViewModel
được cập nhật khisetQuantity
được gọi. Nhưng trước khi gọi bất kỳ phương thức nào hoặc làm việc với bất kỳ dữ liệu nào trongOrderViewModel
, điều quan trọng cần lưu ý là khi kiểm thử giá trị của đối tượngLiveData
, bạn cần phải quan sát các đối tượng để phát hiện thay đổi. Cách đơn giản để thực hiện việc này là sử dụng phương thứcobserveForever
. Gọi phương thứcobserveForever
trên đối tượngquantity
. Phương thức này đòi hỏi một biểu thức lambda, nhưng có thể để trống. - Tiếp đó, gọi phương thức
setQuantity()
, truyền vào12
dưới dạng thông số.
val viewModel = OrderViewModel()
viewModel.quantity.observeForever {}
viewModel.setQuantity(12)
- Chúng ta có thể yên tâm suy diễn rằng giá trị của đối tượng
quantity
là12
. Lưu ý rằng đối tượngLiveData
không phải là chính bản thân giá trị đó. Các giá trị được chứa trong một thuộc tính được gọi làvalue
. Đưa ra nhận định sau:
assertEquals(12, viewModel.quantity.value)
Kiểm thử của bạn sẽ có dạng như sau:
@Test
fun quantity_twelve_cupcakes() {
val viewModel = OrderViewModel()
viewModel.quantity.observeForever {}
viewModel.setQuantity(12)
assertEquals(12, viewModel.quantity.value)
}
Chạy kiểm thử! Xin chúc mừng, bạn vừa viết mã kiểm thử đơn vị LiveData
đầu tiên. Đây là một kỹ năng quan trọng trong việc phát triển Android hiện đại. Kiểm thử này không thử nghiệm nhiều logic kinh doanh, vì vậy, hãy viết mã kiểm thử tương tác nhiều hơn một chút.
Một trong những chức năng chính của OrderViewModel
là tính giá tiền cho đơn đặt hàng của chúng ta. Đó là khi chúng ta chọn số lượng cupcake và ngày nhận hàng. Phép tính giá tiền được thực hiện trong một phương thức riêng tư, do vậy, mã kiểm thử của chúng ta không thể trực tiếp gọi phương thức này ra. Chỉ các phương thức khác trong OrderViewModel
mới có thể gọi lệnh này. Những phương thức này là công khai, cho nên chúng ta sẽ gọi các phương thức đó để kích hoạt phép tính giá tiền, vì vậy, chúng ta có thể kiểm tra xem giá trị của giá tiền có đúng như dự kiến hay không.
Phương pháp hay nhất
Giá tiền được cập nhật khi số lượng cupcake và ngày được chọn. Dù cả hai chức năng này cần được kiểm thử, nhưng tốt hơn hết chỉ nên kiểm thử một chức năng duy nhất. Do đó, chúng ta sẽ thực hiện riêng từng phương thức cho mỗi kiểm thử: một hàm để kiểm thử giá tiền khi số lượng được cập nhật và một hàm riêng rẽ để kiểm thử giá tiền khi ngày được cập nhật. Chúng ta không bao giờ muốn một kiểm thử không cho ra kết quả vì một kiểm thử khác thất bại.
- Tạo một phương thức có tên là
price_twelve_cupcakes()
rồi chú thích phương thức đó là một kiểm thử. - Trong phương thức này, tạo một thực thể của
OrderViewModel
và gọi phương thứcsetQuantity()
, truyền trong 12 dưới dạng một thông số.
val viewModel = OrderViewModel()
viewModel.setQuantity(12)
- Xem xét
PRICE_PER_CUPCAKE
trongOrderViewModel
, chúng ta thấy rằng đơn giá của cupcake là 2 đô la. Chúng ta cũng thấy rằngresetOrder()
được gọi mỗi khi khởi chạyViewModel
và trong phương thức này, ngày mặc định là ngày hôm nay vàPRICE_FOR_SAME_DAY_PICKUP
là 3 đô la. Do vậy, 12 * 2 + 3 = 27. Chúng ta dự kiến rằng giá trị của biếnprice
sau khi chọn 12 cupcake nhỏ sẽ là 27 đô la. Do vậy, hãy cùng khẳng định rằng giá trị dự kiến là 27 đô la bằng với giá trị của đối tượngprice LiveData
.
assertEquals("$27.00", viewModel.price.value)
Bây giờ, hãy chạy kiểm thử.
Có lẽ không thành công!
Kết quả kiểm thử cho biết giá trị thực tế của chúng ta là null
. Có cách giải thích cho điều này. Nếu xem xét biến price
trong OrderViewModel
, bạn sẽ thấy:
val price: LiveData<String> = Transformations.map(_price) {
// Format the price into the local currency and return this as LiveData<String>
NumberFormat.getCurrencyInstance().format(it)
}
Đây là một ví dụ về lý do tại sao LiveData
cần được quan sát trong quá trình kiểm thử. Sử dụng Transformation
để xác định giá trị của price
. Về cơ bản, mã này sẽ lấy giá trị mà chúng ta gán cho price
và chuyển đổi mã đó thành định dạng tiền tệ, nhờ đó ta không phải thực hiện việc này một cách thủ công. Tuy nhiên, mã này còn có các hàm ý khác. Khi chuyển đổi một đối tượng LiveData
, mã này sẽ không được gọi trừ phi đây là điều cực kỳ cần thiết, nhờ đó tiết kiệm tài nguyên trên thiết bị di động. Mã sẽ chỉ được gọi nếu chúng ta quan sát thấy có thay đổi ở đối tượng. Tất nhiên, việc này được thực hiện trong ứng dụng của chúng ta, nhưng cũng cần thực hiện điều tương tự cho kiểm thử này.
- Trong phương thức kiểm thử của bạn, thêm dòng sau trước khi đặt số lượng:
viewModel.price.observeForever {}
Kiểm thử của bạn sẽ có dạng như sau:
@Test
fun price_twelve_cupcakes() {
val viewModel = OrderViewModel()
viewModel.price.observeForever {}
viewModel.setQuantity(12)
assertEquals("$27.00", viewModel.price.value)
}
Nếu chạy kiểm thử, bạn sẽ thành công.
7. Mã giải pháp
8. Xin chúc mừng
Trong lớp học lập trình này, chúng ta:
- Đã tìm hiểu cách thiết lập kiểm thử
LiveData
. - Đã tìm hiểu cách kiểm thử chính bản thân
LiveData
. - Đã tìm hiểu cách kiểm thử
LiveData
đã thay đổi. - Đã tìm hiểu cách quan sát
LiveData
trong một kiểm thử đơn vị.