Tạo bài kiểm tra hệ thống SDV

Kiểm thử hệ thống là bất kỳ kiểm thử SDV nào được tạo bằng Khung kiểm thử SDV.

Tạo bài kiểm thử

Vị trí kiểm thử

  • <test_repository_root>/sample_tests
  • <test_repository_root>/e2e_tests
  • <test_repository_root>/long_running_tests
  • <test_repository_root>/performance_tests
  • <test_repository_root>/hardware

Kiểm tra tệp

  • README.md: Mọi bài kiểm thử đều phải có nội dung mô tả mục đích của bài kiểm thử và cách chạy bài kiểm thử.

  • Tệp kiểm thử: Tất cả các quy trình kiểm thử đều tuân theo một cấu trúc tương tự:

"""SDV Name Test"""

from sdv_test_fw.test_execution import sdv_base_test, sdv_test_runner

class SdvTypeNameTest(sdv_base_test.SdvBaseTestClass):

    def setup_class(self):
      # Setup code. Executed only once at the beginning of the test.
      super().setup_class()
      self.sdv_device1 = self.get_device('device1')
      self.sdv_device2 = self.get_device('device2')
      ...

    # Remove if not needed.
    def setup_test(self):
      super().setup_test()
      # Setup code. Executed before every test case.
      # Remove override if not needed.

    # Remove if not needed.
    def teardown_test(self):
      # Cleanup code. Executed after every test case.
      super().teardown_test()

    # Remove if not needed.
    def teardown_class(self):
      # Cleanup code. Executed once at the end of the test.
      super().teardown_class()

    def test_name_case1(self):
      # Test case step
      # Test case verification

    def test_name_case2(self):
      # Test case step
      # Test case verification

if __name__ == '__main__':
    # Start Test Execution Using SDV Test Framework
    sdv_test_runner.run()
  • Tệp bản dựng: Android.bp. Cấu trúc tệp như sau:
python_test_host {
    name: "SdvTypeNameTest", // Should match the name of the test class.
    main: "sdv_type_name_test.py",
    srcs: [
        "sdv_type_name_test.py",
    ],
    data: [
        ":sdv_test_fw_device_configs",
    ],
    test_options: {
        unit_test: false,
    },
    defaults: [
        "sdv_test_fw_defaults",
    ],
    test_config_template: ":<DEFAULT_TEMPLATE_NAME>",
}

Quy ước đặt tên

Để xác định và tìm các loại kiểm thử, bạn phải tạo kiểm thử theo một quy ước đặt tên cụ thể.

Kiểm thử mẫu

  • Tên tệp: sdv_sample_<NAME>_test.py

  • Tên lớp: SdvSampleNameTest

Thử nghiệm E2E

  • Tên tệp: sdv_e2e_<NAME>_test.py

  • Tên lớp: SdvE2ENameTest

Thử nghiệm kéo dài

  • Tên tệp: sdv_long_running_<NAME>_test.py

  • Tên lớp: SdvLongRunningNameTest

Kiểm thử hiệu suất

  • Tên tệp: sdv_performance_<NAME>_test.py

  • Tên lớp: SdvPerformanceNameTest

Kiểm thử phần cứng

  • Tên tệp: sdv_hw_<NAME>_test.py

  • Tên lớp: SdvHWNameTest

Nguyên tắc về mã

Phần này cung cấp các nguyên tắc và phương pháp hay nhất để viết Kiểm thử hệ thống SDV.

Python và Mobly

Làm quen với hướng dẫn về kiểu Python và các phương pháp hay nhất của Mobly, đồng thời cân nhắc các đề xuất sau đây dành riêng cho SDV:

  • Tránh sử dụng trực tiếp các lệnh nhập Mobly, ngoại trừ các câu lệnh khẳng định. Khung kiểm thử SDV được xây dựng dựa trên khung này và tập trung vào SDV.

  • Xác nhận: Sử dụng trực tiếp các xác nhận của Mobly.

Kiểm thử SDV

Các phần sau đây trình bày các nguyên tắc cụ thể và phương pháp hay nhất để phát triển các bài kiểm thử trong Khung kiểm thử SDV.

Thiết lập và dọn dẹp

Mã thiết lập và mã dọn dẹp phải nằm bên ngoài các trường hợp kiểm thử. Các phương thức teardown được gọi ngay cả khi kiểm thử không thành công, để dọn dẹp thiết bị đúng cách.

Vị trí của mã thiết lập và mã huỷ bỏ phụ thuộc vào nhu cầu cụ thể của kiểm thử, ngay cả khi kiểm thử bị gián đoạn:

  1. Để chạy chỉ một lần ở đầu và cuối toàn bộ quá trình kiểm thử, hãy sử dụng setup_classteardown_class. Ví dụ: lấy thiết bị, đặt các giá trị biến hoặc trạng thái không thay đổi giữa các trường hợp kiểm thử, định cấu hình các thuộc tính chung của thiết bị hoặc đặt cờ.
def setup_class(self):
  super().setup_class()
  # setup code

def teardown_class(self):
  # teardown code
  super().teardown_class()
  1. Để chạy giữa các trường hợp kiểm thử, trước và sau mỗi trường hợp. Ví dụ: phiên tương tác hoặc quá trình thực thi dịch vụ thông thường.
def setup_test(self):
  super().setup_test()
  # setup code

def teardown_test(self):
  # teardown code
  super().teardown_test()

Trường hợp kiểm thử được tham số hoá

Sử dụng các trường hợp kiểm thử được tham số hoá khi các bước là phổ biến trên nhiều trường hợp kiểm thử để tránh lặp lại mã.

from absl.testing import parameterized

@parameterized.named_parameters(
  {
      'testcase_name': 'ab',
      'input1': 'a',
      'input2': 'b',
  },
  {
      'testcase_name': 'cd',
      'input1': 'c',
      'input2': 'd',
  },
  )
  def test_name(self, input1, input2):
    # test

Ví dụ này tạo ra 2 trường hợp kiểm thử test_name_abtest_name_cd.

Một trường hợp kiểm thử để xác minh hành vi

Các trường hợp kiểm thử phải nhỏ gọn và tập trung vào một hành vi cụ thể. Nếu nhiều hành vi có chung các điều kiện tiên quyết hoặc bước, hãy cân nhắc việc chia chúng. Bạn có thể sử dụng setup_test hoặc tham số hoá để giảm thiểu lượng mã lặp lại.

Phương pháp này giúp bạn dễ dàng đọc và gỡ lỗi các kiểm thử vì phương pháp này cho biết rõ những bước và điều kiện nào không thành công.

Ví dụ
test_verify_process():
  device.start_process()

  # precondition 1
  device.send_signal1()
  # verification signal1 received
  ...

  # precondition 2
  device.send_signal2()
  # verification signal2 received
  ...

  # precondition 3
  device.start_agent()
  # verification behavior
  ...

  device.kill_process()
test_setup_test():
  super().setup_test()
  device.start_process()

test_signal1():
  # precondition
  device.send_signal1()
  # verification signal1 received
  ...

test_signal2():
  # precondition
  device.send_signal2()
  # verification signal2 received
  ...

test_agent():
  # precondition
  device.start_agent()
  # verification behavior
  ...

teardown_test():
  device.kill_process()
  super().teardown_test()

Hành vi kiểm thử có tính xác định

Tránh thêm các điều kiện vào thử nghiệm để phân nhánh hành vi của thử nghiệm. Nếu cần chia một quy trình xác minh, hãy sử dụng hai trường hợp kiểm thử riêng biệt.

Không sử dụng các trường hợp ngoại lệ

Các kiểm thử và trình trợ giúp chung phải sử dụng các câu khẳng định thay vì các ngoại lệ. Điều này giúp gỡ lỗi và tuân theo các mẫu kiểm thử.

Ví dụ
result = self.some_calculations()
if result is None:
  raise Exception("No result")
result = self.some_calculations()
self.get_test_validator().assert_is_not_none(result)
Ví dụ
if not self.device.is_subprocess_running(
  self.EXPECTED_PROCESS
):
  raise Exception("Process is not running")
self.get_test_validator().assert_true(
  self.device.is_subprocess_running(self.EXPECTED_PROCESS),
  "Process is not running"
)

Không sử dụng chế độ ngủ

Tránh sử dụng sleep vì thao tác này làm tăng phiên chạy thử nghiệm và gây ra sự không ổn định.

Khi quy trình kiểm thử yêu cầu chờ một sự kiện hoặc quy trình xác minh để tiếp tục, hãy sử dụng Phương thức chờ được cung cấp trong khung.

Hãy sử dụng các phương thức chờ một cách cẩn thận vì phiên chạy thử nghiệm vẫn bị chặn cho đến khi điều kiện trùng khớp hoặc đạt đến thời gian chờ.

Khi bạn cần đợi một điều kiện hoàn tất trong một bài kiểm thử, hãy đặt những câu hỏi sau:

  1. Thời gian chờ hợp lý là bao lâu?

    Nếu một sự kiện dự kiến diễn ra trong một khung thời gian cụ thể, thì thời gian chờ phải khớp với kỳ vọng đó để đảm bảo kiểm thử nhanh chóng không thành công. Giảm thời gian chờ nếu cần (mặc định là 30 giây).

  2. Thao tác do phương thức chờ thực hiện tốn bao nhiêu chi phí?

    Tránh gọi các thao tác tốn kém thường xuyên. Tăng khoảng thời gian thăm dò nếu cần (mặc định là 0,5 giây).

Trường hợp kiểm thử có yêu cầu

Nếu một kiểm thử có các trường hợp kiểm thử có yêu cầu rõ ràng để hoạt động (ví dụ: đích đến mà kiểm thử đó sẽ chạy), bạn có thể bỏ qua các trường hợp đó nếu chúng không đáp ứng các yêu cầu:

def test_with_requirement():
  self.get_test_validator().skip_if(expr, reason)
  # Test case