Dùng đối tượng kiểm thử trong Android

Khi thiết kế chiến lược kiểm thử cho một phần tử hoặc hệ thống, có 3 khía cạnh liên quan đến kiểm thử:

  • Phạm vi: Bài kiểm thử tiếp xúc bao nhiêu phần mã? Các bài kiểm thử có thể xác minh một phương thức duy nhất, toàn bộ ứng dụng hoặc một nơi nào đó ở giữa. Phạm vi được kiểm thử là đang kiểm thử và thường được gọi là Chủ đề đang kiểm thử, cũng như là Hệ thống đang kiểm thử hoặc Đơn vị đang kiểm thử.
  • Tốc độ: Bài kiểm thử chạy nhanh đến mức nào? Tốc độ kiểm thử có thể thay đổi từ mili giây đến vài phút.
  • Độ trung thực: Thử nghiệm "thực tế" đến mức nào? Ví dụ: nếu một phần của mã bạn đang kiểm thử cần tạo một yêu cầu mạng, thì mã kiểm thử đó thực sự tạo yêu cầu mạng này hay là giả mạo kết quả? Nếu kết quả kiểm thử thực sự tương tác với mạng, thì điều đó có nghĩa là kết quả kiểm thử có độ trung thực cao hơn. Đổi lại, việc kiểm thử có thể mất nhiều thời gian hơn để chạy, có thể dẫn đến lỗi nếu mạng ngừng hoạt động hoặc có thể gây tốn kém khi sử dụng.

Xem nội dung cần thử nghiệm để tìm hiểu cách bắt đầu xác định chiến lược thử nghiệm.

Tách biệt và phần phụ thuộc

Khi thử nghiệm một phần tử hoặc hệ thống các phần tử, bạn sẽ thực hiện việc đó để riêng biệt. Ví dụ: để kiểm thử một ViewModel, bạn không cần khởi động trình mô phỏng và khởi chạy giao diện người dùng vì lớp này không (hoặc không nên) phụ thuộc vào khung Android.

Tuy nhiên, đối tượng kiểm thử có thể phụ thuộc vào các đối tượng khác để hoạt động. Ví dụ: ViewModel có thể hoạt động phụ thuộc vào kho lưu trữ dữ liệu.

Khi bạn cần cung cấp phần phụ thuộc cho một đối tượng đang kiểm thử, có một phương pháp phổ biến là tạo một kiểm thử kép (hoặc đối tượng kiểm thử). Kiểm thử kép là các đối tượng trông và đóng vai trò là thành phần trong ứng dụng, nhưng được tạo trong quá trình kiểm thử để cung cấp một hành vi hoặc dữ liệu cụ thể. Ưu điểm chính là các hàm này giúp quá trình kiểm thử của bạn nhanh hơn và đơn giản hơn.

Các loại đối tượng kiểm thử kép

Có nhiều loại kiểm thử kép:

Giả mạo Kiểm thử kép có cách triển khai lớp "đang hoạt động" nhưng được triển khai theo cách phù hợp để kiểm thử nhưng không phù hợp để phát hành chính thức.

Ví dụ: cơ sở dữ liệu trong bộ nhớ.

Dữ liệu giả mạo không yêu cầu khung mô phỏng và có kích thước nhẹ. Chúng được ưu tiên.

Cổ lọ Kiểm thử kép thể hiện cách bạn lập trình để nó hoạt động và có kỳ vọng về hoạt động tương tác của nó. Các mô phỏng sẽ không thực hiện được các bài kiểm thử nếu hoạt động tương tác của các mô-đun đó không phù hợp với các yêu cầu mà bạn xác định. Các bản mô phỏng thường được tạo bằng khung mô phỏng để đạt được tất cả những điều trên.

Ví dụ: Xác minh rằng một phương thức trong cơ sở dữ liệu được gọi chính xác một lần.

Mục thay thế tạm thời Kiểm thử kép thể hiện cách bạn lập trình để nó hoạt động nhưng không kỳ vọng về hoạt động tương tác của nó. Thường được tạo bằng khung mô phỏng. Để đơn giản, chúng tôi ưu tiên nội dung giả mạo thay vì nội dung giả mạo.
Dummy Kiểm thử kép được truyền đi nhưng không được sử dụng, chẳng hạn như khi bạn chỉ cần cung cấp dưới dạng tham số.

Ví dụ: một hàm trống được truyền dưới dạng lệnh gọi lại lượt nhấp.

Gián điệp Trình bao bọc trên một đối tượng thực cũng theo dõi một số thông tin bổ sung, tương tự như mô phỏng. Bạn thường tránh sử dụng các thành phần này để thêm độ phức tạp. Vì vậy, nội dung giả mạo hoặc bắt chước được ưu tiên hơn so với điệp viên.
Shadow Giả sử dụng trong Robolectric.

Ví dụ về cách sử dụng hàng giả

Giả sử bạn muốn kiểm thử đơn vị một ViewModel phụ thuộc vào giao diện có tên là UserRepository và hiển thị tên của người dùng đầu tiên cho một giao diện người dùng. Bạn có thể tạo một kiểm thử giả kép bằng cách triển khai giao diện và trả về dữ liệu đã biết.

object FakeUserRepository : UserRepository {
    fun getUsers() = listOf(UserAlice, UserBob)
}

val const UserAlice = User("Alice")
val const UserBob = User("Bob")

UserRepository giả này không cần phụ thuộc vào nguồn dữ liệu cục bộ và nguồn dữ liệu từ xa mà phiên bản chính thức sẽ sử dụng. Tệp này nằm trong nhóm tài nguyên kiểm thử và sẽ không đi kèm với ứng dụng phát hành chính thức.

Phần phụ thuộc giả mạo có thể trả về dữ liệu đã biết mà không cần phụ thuộc vào các nguồn dữ liệu từ xa
Hình 1: Phần phụ thuộc giả mạo trong kiểm thử đơn vị.

Quy trình kiểm thử sau đây xác minh rằng ViewModel hiển thị chính xác tên người dùng đầu tiên cho khung hiển thị.

@Test
fun viewModelA_loadsUsers_showsFirstUser() {
    // Given a VM using fake data
    val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init

    // Verify that the exposed data is correct
    assertEquals(viewModel.firstUserName, UserAlice.name)
}

Bạn có thể dễ dàng thay thế UserRepository bằng thành phần giả mạo trong bài kiểm thử đơn vị, vì ViewModel là do trình kiểm thử tạo. Tuy nhiên, việc thay thế các thành phần tuỳ ý trong các kiểm thử lớn hơn có thể là một thách thức.

Thay thế các thành phần và tính năng chèn phần phụ thuộc

Khi chương trình kiểm thử không có quyền kiểm soát việc tạo hệ thống đang được kiểm thử, việc thay thế các thành phần để kiểm thử nhân đôi sẽ trở nên phức tạp hơn và đòi hỏi cấu trúc của ứng dụng phải tuân theo một thiết kế có thể kiểm thử.

Ngay cả các chương trình kiểm thử toàn diện, quy mô lớn cũng có thể hưởng lợi từ việc sử dụng kiểm thử kép, chẳng hạn như kiểm thử giao diện người dùng được đo lường điều hướng thông qua luồng người dùng đầy đủ trong ứng dụng của bạn. Trong trường hợp đó, bạn có thể muốn thực hiện kiểm thử thông điệp. Kiểm thử khép kín sẽ tránh được mọi phần phụ thuộc bên ngoài, chẳng hạn như tìm nạp dữ liệu từ Internet. Điều này giúp cải thiện độ tin cậy và hiệu suất.

Hình 2: Một bài kiểm thử lớn bao gồm hầu hết ứng dụng và giả mạo dữ liệu từ xa.

Bạn có thể thiết kế ứng dụng để đạt được tính linh hoạt này theo cách thủ công, nhưng bạn nên sử dụng khung chèn phần phụ thuộc như Hilt để thay thế các thành phần trong ứng dụng tại thời điểm kiểm thử. Xem hướng dẫn kiểm thử Hilt.

Robolectric

Trên Android, bạn có thể sử dụng khung Robolectric, trong đó cung cấp một loại kiểm thử kép đặc biệt. Robolectric cho phép bạn chạy kiểm thử trên máy trạm hoặc trên môi trường tích hợp liên tục. Máy này sử dụng một JVM thông thường, không có trình mô phỏng hay thiết bị. Công cụ này mô phỏng hành vi tăng cường khung hiển thị, tải tài nguyên và các phần khác của khung Android bằng gấp đôi kiểm thử được gọi là shadow (đổ bóng).

Robolectric là một trình mô phỏng nên sẽ không thay thế các chương trình kiểm thử đơn vị đơn giản cũng như không được dùng để kiểm thử khả năng tương thích. Tính năng này cung cấp tốc độ và giảm chi phí nhưng có độ trung thực thấp hơn trong một số trường hợp. Một phương pháp hay khi kiểm thử giao diện người dùng là đảm bảo chúng tương thích với cả Robolectric và kiểm thử đo lường, đồng thời quyết định thời điểm chạy các kiểm thử đó tuỳ thuộc vào nhu cầu kiểm thử chức năng hoặc khả năng tương thích. Cả hai chương trình kiểm thử Espresso và Compose đều có thể chạy trên Robolectric.