Tạo kiểm thử đơn vị cục bộ

Quy trình kiểm thử cục bộ chạy trực tiếp trên máy trạm của riêng bạn thay vì trên thiết bị Android hoặc trình mô phỏng. Do đó, máy ảo Java sẽ sử dụng Máy ảo Java (JVM) cục bộ thay vì một thiết bị Android để chạy kiểm thử. Các bài kiểm thử cục bộ cho phép bạn đánh giá logic của ứng dụng nhanh hơn. Tuy nhiên, việc không thể tương tác với khung Android sẽ tạo ra hạn chế đối với các loại kiểm thử mà bạn có thể chạy.

Kiểm thử đơn vị xác minh hành vi của một phần mã nhỏ, đơn vị kiểm thử. Trình phân tích cú pháp thực thi bằng cách thực thi mã đó và kiểm tra kết quả.

Kiểm thử đơn vị thường đơn giản nhưng cách thiết lập có thể gặp vấn đề khi đơn vị đang kiểm thử không được thiết kế chú trọng đến khả năng kiểm thử:

  • Mã bạn muốn xác minh phải có thể truy cập được qua quy trình kiểm tra. Chẳng hạn, bạn không thể kiểm thử trực tiếp một phương thức riêng tư. Thay vào đó, bạn sẽ kiểm thử lớp này bằng các API công khai của lớp.
  • Để chạy kiểm thử đơn vị ở chế độ tách biệt, các phần phụ thuộc của đơn vị kiểm thử phải được thay thế bằng các thành phần mà bạn kiểm soát, chẳng hạn như thành phần giả mạo hoặc kép kiểm thử khác. Điều này đặc biệt khó khăn nếu mã của bạn phụ thuộc vào khung Android.

Để tìm hiểu về các chiến lược kiểm thử đơn vị phổ biến trong Android, hãy đọc bài viết Nội dung cần kiểm thử.

Vị trí thử nghiệm cục bộ

Theo mặc định, các tệp nguồn để kiểm thử đơn vị cục bộ sẽ được đặt trong module-name/src/test/. Thư mục này đã tồn tại khi bạn tạo một dự án mới bằng Android Studio.

Thêm các phần phụ thuộc kiểm thử

Bạn cũng cần định cấu hình các phần phụ thuộc kiểm thử cho dự án để sử dụng các API tiêu chuẩn do khung kiểm thử JUnit cung cấp.

Để thực hiện việc này, hãy mở tệp build.gradle của mô-đun của ứng dụng và chỉ định các thư viện sau làm phần phụ thuộc. Sử dụng hàm testImplementation để cho biết rằng các giá trị này áp dụng cho nhóm tài nguyên kiểm thử cục bộ chứ không phải cho ứng dụng:

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

Tạo một lớp kiểm thử đơn vị cục bộ

Bạn viết lớp kiểm thử đơn vị cục bộ dưới dạng lớp kiểm thử JUnit 4.

Để thực hiện việc này, hãy tạo một lớp chứa một hoặc nhiều phương thức kiểm thử, thường là trong module-name/src/test/. Phương thức kiểm thử bắt đầu bằng chú thích @Test, đồng thời chứa mã để thực hiện và xác minh một khía cạnh của thành phần mà bạn muốn kiểm thử.

Ví dụ sau minh hoạ cách triển khai một lớp kiểm thử đơn vị cục bộ. Phương thức kiểm thử emailValidator_correctEmailSimple_returnsTrue()sẽ cố gắng xác minh isValidEmail(),một phương thức trong ứng dụng. Hàm kiểm thử sẽ trả về giá trị true nếu isValidEmail() cũng trả về giá trị true.

Kotlin


import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java


import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

Bạn nên tạo các chương trình kiểm thử dễ đọc để đánh giá xem các thành phần trong ứng dụng có trả về kết quả dự kiến hay không. Bạn nên dùng thư viện câu nhận định như junit.Assert, Hamcrest hoặc Truth. Đoạn mã trên là ví dụ về cách sử dụng junit.Assert.

Thư viện Android có thể mô phỏng

Khi bạn thực thi kiểm thử đơn vị cục bộ, Trình bổ trợ Android cho Gradle sẽ bao gồm một thư viện chứa tất cả các API của khung Android, đúng với phiên bản dùng trong dự án của bạn. Thư viện này lưu giữ tất cả các phương thức và lớp công khai của những API đó, nhưng mã bên trong các phương thức đó đã bị xoá. Nếu truy cập được bất kỳ phương thức nào, bài kiểm thử sẽ gửi ra một ngoại lệ.

Điều này cho phép tạo các bài kiểm thử cục bộ khi tham chiếu các lớp trong khung Android, chẳng hạn như Context. Quan trọng hơn, bạn có thể sử dụng một khung mô phỏng với các lớp Android.

Mô phỏng các phần phụ thuộc Android

Một vấn đề điển hình là khi phát hiện một lớp đang sử dụng tài nguyên chuỗi. Bạn có thể nhận tài nguyên chuỗi bằng cách gọi phương thức getString() trong lớp Context. Tuy nhiên, kiểm thử cục bộ không thể sử dụng Context hoặc bất kỳ phương thức nào do các phương thức này thuộc khung Android. Lý tưởng nhất là lệnh gọi đến getString() sẽ được di chuyển khỏi lớp, nhưng điều này không phải lúc nào cũng hiệu quả. Giải pháp cho yêu cầu này là tạo một mô phỏng hoặc một mã giả lập của Context luôn trả về cùng một giá trị khi phương thức getString() được gọi.

Với thư viện Android có thể mô phỏng và các khung mô phỏng như Mockito hoặc MockK, bạn có thể lập trình hành vi của các phiên bản mô phỏng của các lớp Android trong bài kiểm thử đơn vị.

Để thêm đối tượng mô phỏng vào kiểm thử đơn vị cục bộ bằng Mockito, hãy làm theo mô hình lập trình sau:

  1. Đưa phần phụ thuộc thư viện Mockito vào tệp build.gradle, như mô tả trong phần Thiết lập môi trường kiểm thử.
  2. Ở đầu quá trình định nghĩa lớp kiểm thử đơn vị, hãy thêm chú giải @RunWith(MockitoJUnitRunner.class). Chú thích này sẽ yêu cầu trình chạy kiểm thử Mockito xác thực rằng việc bạn sử dụng khung này là chính xác và đơn giản hoá quá trình khởi chạy các đối tượng mô phỏng.
  3. Để tạo đối tượng mô phỏng cho phần phụ thuộc Android, hãy thêm chú thích @Mock trước phần khai báo trường.
  4. Để mã giả lập hành vi của phần phụ thuộc, bạn có thể chỉ định một điều kiện và giá trị trả về khi điều kiện đó được đáp ứng bằng cách sử dụng các phương thức when()thenReturn().

Ví dụ sau cho thấy cách bạn có thể tạo kiểm thử đơn vị sử dụng đối tượng Context mô phỏng trong Kotlin được tạo bằng Mockito-Kotlin.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

Để tìm hiểu thêm về cách sử dụng khung Mockito, hãy xem Tài liệu tham khảo về API Mockito và lớp SharedPreferencesHelperTest trong mã mẫu. Ngoài ra, hãy thử tham gia Lớp học lập trình kiểm thử Android.

Lỗi: "Phương thức ... không được mô phỏng"

Thư viện Android có thể mô phỏng sẽ gửi một trường hợp ngoại lệ nếu bạn cố gắng truy cập vào bất kỳ phương thức nào bằng thông báo Error: "Method ... not mocked.

Nếu các ngoại lệ được gửi có vấn đề đối với việc kiểm thử, thì bạn có thể thay đổi hành vi để các phương thức trả về giá trị rỗng hoặc 0, tuỳ thuộc vào loại dữ liệu trả về. Để thực hiện việc này, hãy thêm cấu hình sau vào tệp build.gradle cấp cao nhất của dự án trong Groovy:

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }