Viết mã kiểm thử đơn vị

1. Trước khi bắt đầu

Trong các lớp học lập trình trước, bạn đã tìm hiểu cách tạo dự án bằng Android Studio, sửa đổi XML để tạo giao diện người dùng tùy chỉnh cho ứng dụng của mình và sửa đổi logic kinh doanh để thêm chức năng. Lớp học lập trình này tập trung vào lý do tại sao việc kiểm thử lại quan trọng và trình bày chi tiết việc kiểm thử đơn vị. Bạn sẽ có cơ hội tìm hiểu về hình thức kiểm thử này cũng như cách thức để viết chương trình kiểm thử tương ứng.

Điều kiện tiên quyết

  • Bạn đã tạo một dự án trong Android Studio.
  • Bạn đã có kinh nghiệm lập trình trên Android Studio.

Kiến thức bạn sẽ học được

  • Tại sao việc kiểm thử lại quan trọng.
  • Thế nào là kiểm thử đơn vị.
  • Cách viết và chạy bài kiểm thử đơn vị.

Bạn cần có

2. Giới thiệu

Do bạn đã viết một số mã Android, nên đã đến lúc tiếp tục với mã kiểm thử. Trước tiên, bạn sẽ tìm hiểu triết lý về kiểm thử, sau đó nghiên cứu kỹ hơn về các bài kiểm thử được tạo tự động trong một dự án Android và cuối cùng là viết ra các bài kiểm thử của riêng bạn cho ứng dụng Đổ xúc xắc! Bài học này có nhiều tài liệu, nhưng đừng lo lắng! Hãy dành thời gian tìm hiểu tài liệu này bởi kiểm thử cần nhiều thời gian và phải thực hành nhiều. Đừng nản chí nếu bạn không thể hiểu rõ vấn đề ngay lập tức.

Tại sao kiểm thử lại quan trọng?

Lúc đầu có thể bạn cho rằng mình không thực sự cần chạy bài kiểm thử trong ứng dụng. Khi ứng dụng có quy mô nhỏ và có chức năng giới hạn, bạn có thể dễ dàng kiểm thử nó theo cách thủ công và xác định xem mọi thứ có hoạt động chính xác hay không. Tuy nhiên, khi ứng dụng phát triển, kiểm thử thủ công sẽ tốn nhiều công sức hơn việc viết kiểm thử tự động. Hơn nữa, khi bắt đầu làm việc với các ứng dụng cấp chuyên nghiệp, việc kiểm thử sẽ trở nên quan trọng khi bạn có cơ sở người dùng lớn. Bạn phải tính toán để nhiều loại thiết bị khác nhau chạy nhiều phiên bản Android khác nhau. Cuối cùng, bạn có đạt đến ngưỡng mà tại đó, các bài kiểm thử tự động có thể chiếm phần lớn các kịch bản tình huống sử dụng với tốc độ nhanh hơn đáng kể so với kiểm thử thủ công. Khi bạn chạy bài kiểm thử trước khi phát hành mã mới, bạn có thể thay đổi mã hiện tại để tránh phát hành ứng dụng có cách thức hoạt động ngoài mong muốn. Hãy nhớ kiểm thử tự động là các bài kiểm thử được thực thi thông qua phần mềm, trái với kiểm thử thủ công qua tương tác trực tiếp với một thiết bị. Kiểm thử tự động và kiểm thử thủ công đóng vai trò quan trọng trong việc đảm bảo người dùng sản phẩm có được trải nghiệm thú vị. Tuy nhiên, kiểm thử tự động có thể chính xác hơn và có thể tối ưu hóa năng suất của nhóm bạn bởi vì không cần người chạy các phép kiểm thử và chúng có thể được thực thi nhanh hơn nhiều so với kiểm thử thủ công.

Tìm hiểu kỹ hơn về kiểm thử đơn vị

Trong lớp học lập trình này, bạn cần tập trung vào các bài kiểm thử đơn vị. Bạn sẽ thực hiện các bài kiểm thử đo lường sau đó. Để bắt đầu, bạn phải tìm hiểu các bài kiểm thử được tạo ra khi bạn tạo một ứng dụng Android thông qua Android Studio. Bạn cũng sẽ có được kinh nghiệm thực tế về chạy các bài kiểm thử và dần làm quen với việc viết mã kiểm thử.

Trong lộ trình trước đó, bạn đã tìm hiểu cách tìm tệp nguồn để kiểm thử. Các bài kiểm thử đơn vị luôn nằm trong thư mục test:

f02b380da4e8f661.png

  1. Mở tệp app/build.gradle và tìm hiểu các phần phụ thuộc. Bạn sẽ thấy một số phần phụ thuộc được đánh dấu là testImplementationandroidTestImplementation, tương ứng với kiểm thử đo lường và đơn vị. Lưu ý:

app/build.gradle

testImplementation 'junit:junit:4.12'

Thư viện JUnit thúc đẩy các bài kiểm thử đơn vị và cho phép bạn đánh dấu mã là kiểm thử để bạn có thể biên dịch và chạy mã theo cách nó có thể kiểm thử mã ứng dụng.

  1. Trong thư mục test, hãy mở tệp ExampleUnitTest.kt.

Bạn sẽ thấy một kiểm thử đơn vị mẫu giống như sau:

ExampleUnitTest.kt

class ExampleUnitTest {
   @Test
   fun addition_isCorrect() {
       assertEquals(4, 2 + 2)
   }
}

Mặc dù đã thêm một số mã vào ứng dụng Đổ xúc xắc nhưng có thể bạn chưa viết kiểm thử nào. Do đó, không có gì ngoài một số mã chung do Android Studio tạo tự động. Đây là kiểm thử tùy ý đóng vai trò là trình giữ chỗ cho các bài kiểm thử phù hợp hơn mà nhà phát triển dự định sẽ viết. Hiện tại, khối mã này chỉ kiểm thử rằng 2 + 2 = 4. Tất nhiên, điều này luôn đúng. Tìm hiểu kỹ hơn về những gì đang diễn ra:

  • Trước tiên, bạn phải chú thích các chức năng kiểm thử bằng chú thích @ Test được nhập từ thư viện org.junit.test. Bạn có thể coi chú thích là thẻ siêu dữ liệu cho một đoạn mã có thể thay đổi cách mã đó được biên soạn. Trong trường hợp này, chú thích @Test sẽ cho trình biên dịch biết rằng phương thức sau đây là một kiểm thử và kiểm thử đó cho phép nó chạy như vậy.

Sau chú thích, bạn có một nội dung khai báo hàm. Trong trường hợp này là hàm addition_isCorrect(). Trong hàm này, hàm assertEquals() xác nhận một giá trị dự kiến phải bằng một giá trị thực tế thu được thông qua logic kinh doanh. Các phương pháp xác nhận là mục tiêu cuối cùng của một kiểm thử đơn vị. Cuối cùng, bạn phải xác nhận một kết quả có được từ mã đang ở một trạng thái cụ thể. Nếu trạng thái của kết quả khớp với trạng thái dự kiến, thì kiểm thử đạt. Nếu trạng thái của kết quả không khớp với trạng thái dự kiến, thì kiểm thử không đạt. Trong trường hợp này, mã đang so sánh hai giá trị, vì vậy phương thức assertEquals() nhận hai thông số — một giá trị dự kiến và một giá trị thực tế. Đúng như tên gọi, giá trị dự kiến là giá trị mà bạn mong đợi, trong trường hợp này là 4. Giá trị thực tế đại diện cho kết quả của một đoạn mã thực tế. Nói chung, thao tác này sẽ kiểm thử một đoạn mã từ chính ứng dụng. Trong trường hợp này, đó chỉ là một đoạn mã tuỳ ý, ví dụ: 2 + 2. Nếu không cần làm gì thêm, hãy chạy bài kiểm thử này để xem điều gì sẽ xảy ra.

Có nhiều cách chạy bài kiểm thử trong Android Studio mà bạn sẽ tìm hiểu sau này. Bây giờ bạn chưa cần tìm hiểu sâu.

  1. Bên cạnh phần khai báo phương thức addition_isCorrect, hãy nhấp vào các mũi tên, sau đó chọn Run ‘ExampleUnitTest.addition_isCorrect' (Chạy ‘ExampleUnitTest.addition_isCorrect').

78c943e851a33644.png

Đây được gọi là kiểm thử dương. Nói cách khác, xác nhận nằm trong lời khẳng định. 2 + 2 bằng 4. Ngoài ra, chúng ta có thể viết kiểm thử âm để đưa ra khẳng định bằng lời phủ định. Ví dụ: 2 + 2 không bằng 5.

Trong ngăn Run (Chạy), bạn sẽ thấy một nội dung tương tự như ảnh chụp màn hình này:

190df0c8ff787233.png

Có nhiều chỉ báo cho thấy kiểm thử đã thành công, cụ thể là các dấu kiểm thử màu xanh lục và số lượng kiểm thử đã đạt.

aa7d361d8e4826ef.png

  1. Sửa đổi kiểm thử để xem lỗi sẽ xảy ra như thế nào. Hãy thay đổi 2 + 2 thành 2 + 3, sau đó thực thi lại. Lưu ý bạn chỉ đang thử nghiệm với mã được tạo nhằm có được kinh nghiệm về cách kiểm thử hoạt động. Những thay đổi này không liên quan gì đến khả năng hoạt động của ứng dụng Đổ xúc xắc.

ExampleUnitTest.kt

class ExampleUnitTest {
   @Test
   fun addition_isCorrect() {
       assertEquals(4, 2 + 3)
   }
}

Sau khi chạy phần còn lại, bạn sẽ thấy nội dung tương tự như ảnh chụp màn hình sau:

751ac8089cf4c47c.png

Văn bản màu đỏ cho biết kiểm thử không đạt. Trong trình đơn kết quả kiểm thử, nhấp vào các mục sẽ cho ra thông báo lỗi cho biết lý do kiểm thử không đạt.

163708373e651ecc.png

Trong trường hợp này, thông báo cho biết xác nhận không thành công vì kết quả dự kiến là 4, nhưng giá trị thực là 5. Điều này có nghĩa bạn đã thay đổi giá trị thực tế thành 2 + 3, nhưng bạn đã để nguyên giá trị dự kiến là 4. Bạn cũng có thể thấy dòng kiểm thử không đạt. Trong trường hợp này là dòng 15, được biểu thị là ExampleUnitTest.kt:15.

  1. Để chắc chắn, hãy thay đổi giá trị dự kiến từ 4 thành 5 và chạy lại kiểm thử. Kiểm thử bây giờ sẽ ở trạng thái đạt khi giá trị dự kiến khớp với kết quả thực tế của mã được đề cập.

3. Viết đoạn mã kiểm thử đơn vị đầu tiên của bạn

Bây giờ khi đã làm quen với khái niệm kiểm thử đơn vị, bạn có thể viết kiểm thử đơn vị của mình phù hợp hơn với ứng dụng Đổ xúc xắc.

Như đã biết, chức năng chính của ứng dụng Đổ xúc xắc dựa trên trình tạo số ngẫu nhiên. Rất tiếc, trình tạo số ngẫu nhiên rất khó kiểm thử vì bạn không thể chắc chắn về kết quả của số được tạo ngẫu nhiên. Mục tiêu của việc kiểm thử này là để đảm bảo khi tung xúc xắc hoặc gọi phương thức roll trên lớp dice, bạn sẽ nhận lại một số thích hợp. Kiểm thử bạn viết chỉ kiểm tra kết quả của trình tạo số ngẫu nhiên là một số nằm trong phạm vi bạn đã chỉ định cho trình tạo.

  1. Trong tệp ExampleUnitTest.kt, hãy xóa phương thức kiểm thử đã tạo và nhập các câu lệnh. Bây giờ, tệp của bạn sẽ giống như sau:

c06e8b402f293b5e.png

  1. Tạo hàm generates_number():

ExampleUnitTest.kt

fun generates_number() {
}
  1. Chú thích phương thức generates_number() bằng chú thích @Test. Lưu ý khi bạn cố gọi @Test, văn bản sẽ có màu đỏ. Lý do là bởi nó không tìm thấy nội dung khai báo của chú thích này, do đó bạn cần nhập chú thích. Bạn có thể thực hiện việc này một cách tự động khi nhấn Control+Enter (hoặc Options+Return trên máy Mac).

Nếu nhấp vào dòng mã, bạn sẽ thấy lời nhắc nhập:

bbe5791b9565588c.png

Ngoài ra, bạn cũng có thể sao chép và dán tệp import org.junit.Test sau tên gói, nhưng trước khi khai báo lớp. Bây giờ, mã sẽ giống như sau:

9a94c2bdf84adb61.png

  1. Tạo một bản sao của đối tượng Dice.

ExampleUnitTest.kt

@Test
fun generates_number() {
   val dice = Dice(6)
}
  1. Tiếp theo, hãy gọi phương thức roll() trên bản sao này và lưu trữ giá trị được trả về.

ExampleUnitTest.kt

@Test
fun generates_number() {
   val dice = Dice(6)
   val rollResult = dice.roll()
}
  1. Cuối cùng, hãy đưa ra một câu khẳng định thực tế. Nói cách khác, bạn cần xác nhận phương thức này trả về một giá trị nằm trong số cạnh mà bạn đã đưa vào. Vì vậy, trong trường hợp này, giá trị cần lớn hơn 0 và nhỏ hơn 7. Để thực hiện việc này, hãy sử dụng phương thức assertTrue(). Lưu ý khi bạn cố gắng gọi phương thức assertTrue(), trước tiên, văn bản sẽ có màu đỏ. Điều này là do không thể tìm thấy phần khai báo của phương thức này, vì vậy bạn cần nhập vào, tương tự như những gì bạn đã gặp với chú thích.

10eea07fc21bf998.png

Bạn có thể tự động nhập nó như đã thảo luận trước đó. Tuy nhiên, cần lưu ý rằng lần này bạn có nhiều tuỳ chọn để lựa hơn. Trong trường hợp này, đó phải là tuỳ chọn trong gói org.junit.Assert:

5dbfba2ba0e37ac9.png

Ngoài ra, bạn có thể dán mã này sau câu lệnh nhập cho chú thích kiểm thử:

ExampleUnitTest.kt

import org.junit.Assert.assertTrue

Mã của bạn hiện có trông như sau:

347f792f455ae6b5.png

Nếu đặt con trỏ giữa các dấu ngoặc đơn sau đó nhấn Control+P (hoặc Command+P trên máy Mac), bạn sẽ thấy chú giải công cụ cho biết phương thức sử dụng các tham số nào:

865cf0ac47738e08.png

Phương thức assertTrue() có hai thông số: StringBoolean. Nếu xác nhận không thành công, thì chuỗi sẽ là một thông báo hiển thị trên bảng điều khiển. Boolean là một câu lệnh có điều kiện. Đặt thông báo thành:

ExampleUnitTest.kt

"The value of rollResult was not between 1 and 6"

Như đã đề cập trước đó, việc kiểm thử các số ngẫu nhiên là một thử thách bởi không thể dự đoán được giá trị của nó do tính chất ngẫu nhiên. Bạn chỉ cần đảm bảo rằng giá trị nằm trong một phạm vi cụ thể. Đặt thông số điều kiện thành:

ExampleUnitTest.kt

rollResult in 1..6

Mã sẽ có dạng như sau:

ExampleUnitTest.kt

@Test
fun generates_number() {
   val dice = Dice(6)
   val rollResult = dice.roll()
   assertTrue("The value of rollResult was not between 1 and 6", rollResult in 1..6)
}
  1. Nhấp vào các mũi tên bên cạnh hàm rồi chọn Run ‘ExampleUnitTest.generates_number()' (Chạy ‘ExampleUnitTest.generates_number()').

Nếu mã của bạn giống như đoạn mã trước đó, kiểm thử của bạn đã đạt!

  1. Không bắt buộc: Để thực hành thêm, hãy sửa đổi xúc xắc thành 4 hoặc 5 mặt mà không thay đổi xác nhận để thấy kiểm thử không đạt.

4. Xin chúc mừng

Bạn đã tìm hiểu:

  • Tầm quan trọng của kiểm thử.
  • Kiểm thử đơn vị là như thế nào.
  • Cách chạy bài kiểm thử đơn vị.
  • Một số cú pháp kiểm thử phổ biến.
  • Cách viết kiểm thử đơn vị.

Tìm hiểu thêm