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

Bài 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ị hoặc trình mô phỏng Android. Do đó, khung này sử dụng Máy ảo Java (JVM) cục bộ thay vì thiết bị Android để chạy kiểm thử. 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 giới hạn về 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 nhỏ mã, đơn vị đang được kiểm thử. Để làm việc này, Gemini sẽ thực thi đoạn mã đó và kiểm tra kết quả.

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

  • Mã mà bạn muốn xác minh cần phải truy cập được từ một chương trình kiểm thử. Ví dụ: bạn không thể trực tiếp kiểm thử một phương thức riêng tư. Thay vào đó, bạn kiểm thử lớp bằng cách sử dụng các API công khai của lớp đó.
  • Để chạy kiểm thử đơn vị riêng biệt, bạn phải thay thế các phần phụ thuộc của đơn vị đang được kiểm thử bằng các thành phần mà bạn kiểm soát, chẳng hạn như bản mô phỏng hoặc bản kiểm thử khác. Điều này đặc biệt có vấ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í của kiểm thử cục bộ

Theo mặc định, các tệp nguồn cho kiểm thử đơn vị cục bộ đượ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.

Để làm việc này, hãy mở tệp build.gradle của mô-đun ứ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 phần phụ thuộc áp dụng cho nhóm tài nguyên kiểm thử cục bộ chứ không phải ứ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.

Để làm 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 và chứa mã để thực thi 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 đây 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() cố gắng xác minh isValidEmail(),đây là một phương thức trong ứng dụng. Hàm kiểm thử sẽ trả về true nếu isValidEmail() cũng trả về 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 kiểm thử dễ đọc để đánh giá xem các thành phần trong ứng dụng có trả về kết quả như mong đợi hay không. Bạn nên sử dụng thư viện câu nhận định như junit.Assert, Hamcrest hoặc Truth. Đoạn mã trên là một 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ả API của khung Android, chính xác với phiên bản được dùng trong dự án của bạn. Thư viện này chứa 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 vào bất kỳ phương thức nào, thì kiểm thử sẽ gửi ra một ngoại lệ.

Điều này cho phép tạo các kiểm thử cục bộ khi tham chiếu các lớp trong khung Android như Context. Quan trọng hơn, việc này cho phép bạn sử dụng 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 đề thường gặp là khi bạn phát hiện thấy một lớp đang sử dụng tài nguyên chuỗi. Bạn có thể lấy 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 của lớp này vì chúng thuộc khung Android. Tốt nhất là lệnh gọi đến getString() sẽ được di chuyển ra khỏi lớp, nhưng không phải lúc nào cũng thực hiện được. Giải pháp 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ủa nó đượ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 mô phỏng của các lớp Android trong 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. Thêm 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 thử nghiệm.
  2. Ở đầu định nghĩa lớp kiểm thử đơn vị, hãy thêm chú thích @RunWith(MockitoJUnitRunner.class). Chú thích này yêu cầu trình chạy kiểm thử Mockito xác thực rằng bạn sử dụng khung đúng cách và đơn giản hoá việc khởi chạy đố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ô phỏng hành vi của phần phụ thuộc, bạn có thể chỉ định một điều kiện và trả về giá trị khi điều kiện đó được đáp ứng bằng cách sử dụng các phương thức when() và thenReturn().

Ví dụ sau đây cho thấy cách bạn có thể tạo một 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 về 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 ngoại lệ nếu bạn cố gắng truy cập vào bất kỳ phương thức nào của thư viện đó bằng thông báo Error: "Method ... not mocked.

Nếu các ngoại lệ được gửi gây ra vấn đề cho các kiểm thử, bạn có thể thay đổi hành vi để các phương thức trả về giá trị rỗng hoặc bằng 0, tuỳ thuộc vào kiểu 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
  }