Ví dụ về kiểm thử tự đo lường

Khi một kiểm thử đo lường bắt đầu, gói mục tiêu của kiểm thử đó sẽ được khởi động lại bằng mã đo lường được chèn và bắt đầu thực thi. Có một ngoại lệ là gói mục tiêu ở đây không phải là chính khung ứng dụng Android, chẳng hạn như gói android, vì làm như vậy sẽ dẫn đến trường hợp nghịch lý là khung Android cần phải khởi động lại. Đây là lớp hỗ trợ các chức năng của hệ thống, bao gồm cả chính khả năng đo lường.

Điều này có nghĩa là một kiểm thử đo lường không thể tự chèn chính nó vào khung Android (còn gọi là máy chủ hệ thống) để thực thi. Để kiểm thử khung Android, mã kiểm thử chỉ có thể gọi các giao diện API công khai hoặc các giao diện được hiển thị bằng Ngôn ngữ định nghĩa giao diện Android (AIDL) có trong cây nguồn của nền tảng. Đối với danh mục kiểm thử này, việc nhắm đến bất kỳ gói cụ thể nào cũng không có ý nghĩa. Do đó, thông thường, các công cụ đo lường như vậy sẽ được khai báo để nhắm đến gói ứng dụng kiểm thử riêng, như được xác định trong thẻ <manifest> của AndroidManifest.xml.

Tuỳ thuộc vào yêu cầu, các gói ứng dụng kiểm thử trong danh mục này cũng có thể:

  • Cần có các hoạt động gói để kiểm thử.
  • Chia sẻ mã nhận dạng người dùng với hệ thống.
  • Được ký bằng khoá nền tảng.
  • Được biên dịch dựa trên nguồn khung thay vì SDK công khai.

Danh mục kiểm thử đo lường này đôi khi được gọi là tự đo lường. Sau đây là một số ví dụ về kiểm thử tự đo lường trong nguồn nền tảng:

Ví dụ được đề cập ở đây là viết một kiểm thử đo lường mới với gói mục tiêu được đặt tại gói ứng dụng kiểm thử của riêng nó. Hướng dẫn này sử dụng quy trình kiểm thử sau đây làm ví dụ:

Bạn nên duyệt qua mã trước để có được ấn tượng sơ bộ trước khi tiếp tục.

Quyết định vị trí nguồn

Thông thường, nhóm của bạn sẽ có sẵn một mẫu gồm các địa điểm để đăng ký mã kiểm thử và các địa điểm để thêm kiểm thử. Hầu hết các nhóm đều sở hữu một kho lưu trữ git hoặc chia sẻ một kho lưu trữ với các nhóm khác nhưng có một thư mục con chuyên dụng chứa mã nguồn thành phần.

Giả sử vị trí gốc cho nguồn thành phần của bạn là <component source root>, hầu hết các thành phần đều có thư mục srctests bên dưới, cùng một số tệp bổ sung như Android.mk (hoặc được chia thành các tệp .mk bổ sung), tệp kê khai AndroidManifest.xml và tệp cấu hình kiểm thử "AndroidTest.xml".

Vì bạn đang thêm một chương trình kiểm thử hoàn toàn mới, nên có thể bạn sẽ cần tạo thư mục tests bên cạnh thành phần src và điền nội dung vào thư mục đó.

Trong một số trường hợp, nhóm của bạn có thể có thêm cấu trúc thư mục trong tests do cần đóng gói nhiều bộ kiểm thử thành các tệp apk riêng lẻ. Và trong trường hợp này, bạn cần tạo một thư mục con mới trong tests.

Bất kể cấu trúc là gì, bạn sẽ điền sẵn các tệp tương tự như nội dung trong thư mục instrumentation vào thay đổi về trình tự mẫu vào thư mục tests hoặc thư mục con mới tạo. Thông tin chi tiết về từng tệp sẽ được giải thích ở phần sau của tài liệu này.

Tệp kê khai

Cũng như dự án ứng dụng, mỗi mô-đun kiểm thử đo lường đều yêu cầu một tệp kê khai có tên là AndroidManifest.xml. Để tự động đưa tệp này vào bằng tệp makefile lõi BUILD_PACKAGE, hãy cung cấp tệp này bên cạnh tệp Android.mk cho mô-đun kiểm thử.

Nếu bạn chưa quen với tệp AndroidManifest.xml, hãy tham khảo nội dung Tổng quan về tệp kê khai ứng dụng

Sau đây là tệp AndroidManifest.xml mẫu:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

Một số nhận xét chọn lọc trong tệp kê khai:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

Thuộc tính package là tên gói ứng dụng: đây là giá trị nhận dạng duy nhất mà khung ứng dụng Android sử dụng để xác định một ứng dụng (hoặc trong ngữ cảnh này: ứng dụng kiểm thử của bạn). Mỗi người dùng trong hệ thống chỉ có thể cài đặt một ứng dụng có tên gói đó.

Hơn nữa, thuộc tính package này giống với thuộc tính mà ComponentName#getPackageName() trả về, cũng như thuộc tính mà bạn sẽ sử dụng để tương tác với nhiều lệnh con pm sử dụng adb shell.

Lưu ý rằng mặc dù tên gói thường có cùng kiểu với tên gói Java, nhưng thực tế thì tên gói này có rất ít liên quan. Nói cách khác, gói ứng dụng (hoặc kiểm thử) của bạn có thể chứa các lớp có tên gói bất kỳ, mặc dù mặt khác, bạn có thể chọn đơn giản và đặt tên gói Java cấp cao nhất trong ứng dụng hoặc kiểm thử giống với tên gói ứng dụng.

android:sharedUserId="android.uid.system"

Điều này khai báo rằng tại thời điểm cài đặt, tệp APK này phải được cấp cùng một mã nhận dạng người dùng, tức là danh tính thời gian chạy, như nền tảng cốt lõi. Xin lưu ý rằng điều này phụ thuộc vào việc tệp APK được ký bằng cùng một chứng chỉ với nền tảng cốt lõi (xem LOCAL_CERTIFICATE trong phần trước), nhưng chúng là các khái niệm khác nhau:

  • một số quyền hoặc API được bảo vệ bằng chữ ký, yêu cầu cùng một chứng chỉ ký
  • một số quyền hoặc API yêu cầu danh tính người dùng system của phương thức gọi, yêu cầu gói gọi chia sẻ mã nhận dạng người dùng với system, nếu đó là một gói riêng biệt với chính nền tảng cốt lõi
<uses-library android:name="android.test.runner" />

Điều này là bắt buộc đối với tất cả các kiểm thử đo lường vì các lớp liên quan được đóng gói trong một tệp thư viện JAR khung riêng biệt, do đó, cần có thêm các mục nhập đường dẫn lớp khi gói kiểm thử được khung ứng dụng gọi.

android:targetPackage="android.test.example.helloworld"

Bạn có thể nhận thấy targetPackage ở đây được khai báo giống với thuộc tính package được khai báo trong thẻ manifest của tệp này. Như đã đề cập trong phần kiến thức cơ bản về kiểm thử, danh mục kiểm thử đo lường này thường dành cho việc kiểm thử API khung, vì vậy, việc có một gói ứng dụng được nhắm mục tiêu cụ thể (ngoài chính gói đó) là không có ý nghĩa.

Tệp cấu hình đơn giản

Mỗi mô-đun kiểm thử mới phải có một tệp cấu hình để hướng dẫn hệ thống xây dựng bằng siêu dữ liệu mô-đun, các phần phụ thuộc tại thời điểm biên dịch và hướng dẫn đóng gói. Trong hầu hết các trường hợp, tuỳ chọn tệp Blueprint dựa trên Soong là đủ. Để biết thông tin chi tiết, hãy xem phần Cấu hình kiểm thử đơn giản.

Tệp cấu hình phức tạp

Đối với những trường hợp phức tạp hơn này, bạn cũng cần viết tệp cấu hình kiểm thử cho khai thác kiểm thử của Android, Trade Federation.

Cấu hình kiểm thử có thể chỉ định các tuỳ chọn thiết lập thiết bị đặc biệt và các đối số mặc định để cung cấp lớp kiểm thử. Xem ví dụ tại /platform_testing/tests/example/instrumentation/AndroidTest.xml.

Để thuận tiện, chúng tôi cung cấp một bản tổng quan nhanh tại đây:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

Một số nhận xét chọn lọc về tệp cấu hình kiểm thử:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

Thao tác này sẽ yêu cầu Trade Federation cài đặt HelloWorldTests.apk trên thiết bị mục tiêu bằng cách sử dụng target_preparer đã chỉ định. Có nhiều trình chuẩn bị mục tiêu dành cho nhà phát triển trong Trade Federation và bạn có thể sử dụng các trình này để đảm bảo thiết bị được thiết lập đúng cách trước khi thực thi kiểm thử.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Thao tác này chỉ định lớp kiểm thử Trade Federation để sử dụng nhằm thực thi kiểm thử và truyền trong gói trên thiết bị sẽ được thực thi và khung trình chạy kiểm thử là JUnit trong trường hợp này.

Để biết thêm thông tin, hãy xem phần Kiểm thử cấu hình mô-đun.

Tính năng JUnit4

Việc sử dụng thư viện android-support-test làm trình chạy kiểm thử cho phép sử dụng các lớp kiểm thử kiểu JUnit4 mới và thay đổi gerrit mẫu chứa một số cách sử dụng rất cơ bản các tính năng của thư viện này. Xem ví dụ tại /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java.

Mặc dù các mẫu kiểm thử thường dành riêng cho các nhóm thành phần, nhưng có một số mẫu sử dụng thường hữu ích.

@RunWith(JUnit4.class)
public class HelloWorldTest {

Một điểm khác biệt đáng kể trong JUnit4 là các bài kiểm thử không còn bắt buộc phải kế thừa từ một lớp kiểm thử cơ sở chung; thay vào đó, bạn viết các bài kiểm thử trong các lớp Java thuần tuý và sử dụng chú thích để chỉ ra một số quy tắc thiết lập và quy tắc ràng buộc nhất định của kiểm thử. Trong ví dụ này, chúng tôi hướng dẫn rằng lớp này nên được chạy dưới dạng kiểm thử JUnit4.

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

Chú thích @Before@After được JUnit4 sử dụng trên các phương thức để thực hiện việc thiết lập trước kiểm thử và gỡ bỏ sau kiểm thử. Tương tự, chú thích @BeforeClass@AfterClass được JUnit4 sử dụng trên các phương thức để thiết lập trước khi thực thi tất cả các bài kiểm thử trong một lớp kiểm thử và sau đó huỷ thiết lập. Xin lưu ý rằng các phương thức thiết lập và gỡ bỏ trong phạm vi lớp phải là tĩnh. Đối với các phương thức kiểm thử, không giống như trong phiên bản trước đó của JUnit, các phương thức này không cần bắt đầu tên phương thức bằng test nữa. Thay vào đó, mỗi phương thức phải được chú thích bằng @Test. Như thường lệ, các phương thức kiểm thử phải công khai, không khai báo giá trị trả về, không nhận tham số và có thể gửi ngoại lệ.

Quyền truy cập vào lớp đo lường

Mặc dù không được đề cập trong ví dụ cơ bản về hello world, nhưng khá phổ biến khi một bài kiểm thử Android yêu cầu quyền truy cập vào thực thể Instrumentation: đây là giao diện API cốt lõi cung cấp quyền truy cập vào ngữ cảnh ứng dụng, các API kiểm thử liên quan đến vòng đời hoạt động và nhiều API khác.

Vì các kiểm thử JUnit4 không còn yêu cầu lớp cơ sở chung, nên bạn không cần phải lấy thực thể Instrumentation thông qua InstrumentationTestCase#getInstrumentation() nữa. Thay vào đó, trình chạy kiểm thử mới sẽ quản lý thực thể này thông qua InstrumentationRegistry, nơi lưu trữ chế độ thiết lập môi trường và ngữ cảnh do khung đo lường tạo.

Để truy cập vào thực thể của lớp Instrumentation, bạn chỉ cần gọi phương thức tĩnh getInstrumentation() trên lớp InstrumentationRegistry:

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

Tạo bản dựng và kiểm thử cục bộ

Đối với các trường hợp sử dụng phổ biến nhất, hãy triển khai Atest (Kiểm thử).

Đối với các trường hợp phức tạp hơn đòi hỏi phải tuỳ chỉnh nhiều hơn, hãy làm theo hướng dẫn đo lường.