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

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 trình mô phỏng hoặc thiết bị Android. Do đó, ứng dụng này sử dụng Máy ảo Java (JVM) cục bộ của bạn, thay vì dùng thiết bị Android để chạy kiểm thử. Thử nghiệm 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 tạo ra sự giới hạn về các loại kiểm thử 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ị trong thử nghiệm. Để thực hiện điều đó, ứng dụng sẽ thực thi 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ã bạn muốn xác minh cần có thể truy cập được từ một chương trình kiểm thử. Ví dụ: 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 bằng các API công khai của nó.
  • Để chạy kiểm thử đơn vị ở chế độ tách biệt, các phần phụ thuộc của đơn vị đang 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ư các thành phần giả mạo hoặc thành phần kiểm thử đôi 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 thử nghiệm.

Địa điểm 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.

Để thực hiện việc này, hãy mở tệp build.gradle của mô-đun ứng dụng và chỉ định nội dung sau thư viện 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 này á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 như vậ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 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 chương trình kiểm thử dễ đọc để đánh giá xem các thành phần trong ứng dụng trả về kết quả dự kiến. Bạn nên sử dụng thư viện xác nhận 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 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 các API đó, nhưng mã bên trong các phương thức đã bị xoá. Nếu bất kỳ phương thức nào được truy cập, 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, thư viện 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à 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 Context . Tuy nhiên, quy trình 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 nó vì chúng đều thuộc khung Android. Lý tưởng nhất là lệnh gọi đến getString() sẽ được di chuyển ra khỏi lớp, nhưng điều này không phải lúc nào cũng thực tế. Giải pháp là tạo một mô phỏng hoặc một mô-đun 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 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 kiểm thử.
  2. Ở đầu phần khai báo 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 này đúng cách và đơn giản hoá việc 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ú giải @Mock trước khi khai báo trường.
  4. Để tạo 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à 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 đây cho thấy cách bạn có thể tạo một kiểm thử đơn vị sử dụng một bản mô phỏng Đối tượng Context 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 API Mockito tham chiếu 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 pháp ... không được mô phỏng"

Thư viện Android mô phỏng sẽ đưa ra trường hợp ngoại lệ nếu bạn cố truy cập vào bất kỳ với thông báo Error: "Method ... not mocked.

Nếu các ngoại lệ được gửi trở nên khó khăn cho thử nghiệm của bạn, bạn có thể thay đổi để các phương thức thay vì 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
  }