Pembuatan uji sistem SDV

Pengujian sistem mengacu pada pengujian SDV yang dibuat menggunakan Framework Pengujian SDV.

Pembuatan pengujian

Lokasi pengujian

  • <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

Menguji file

  • README.md: Semua pengujian harus menyertakan deskripsi tujuan pengujian dan cara menjalankan pengujian.

  • File pengujian: Semua pengujian mengikuti struktur yang serupa:

"""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()
  • File build: Android.bp. Struktur filenya adalah sebagai berikut:
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>",
}

Konvensi penamaan

Untuk mengidentifikasi dan menemukan berbagai jenis pengujian, pengujian harus dibuat dengan mengikuti konvensi penamaan tertentu.

Pengujian contoh

  • Nama file: sdv_sample_<NAME>_test.py

  • Nama class: SdvSampleNameTest

Pengujian E2E

  • Nama file: sdv_e2e_<NAME>_test.py

  • Nama class: SdvE2ENameTest

Pengujian yang berjalan lama

  • Nama file: sdv_long_running_<NAME>_test.py

  • Nama class: SdvLongRunningNameTest

Pengujian performa

  • Nama file: sdv_performance_<NAME>_test.py

  • Nama class: SdvPerformanceNameTest

Pengujian hardware

  • Nama file: sdv_hw_<NAME>_test.py

  • Nama class: SdvHWNameTest

Panduan kode

Bagian ini memberikan panduan dan praktik terbaik untuk menulis Pengujian Sistem SDV.

Python dan Mobly

Pelajari panduan gaya Python dan praktik terbaik Mobly, serta pertimbangkan rekomendasi khusus SDV berikut:

  • Hindari penggunaan impor Mobly secara langsung, kecuali untuk pernyataan. Framework Pengujian SDV dibuat berdasarkan hal tersebut dengan fokus pada SDV.

  • Pernyataan: Gunakan pernyataan Mobly secara langsung.

Pengujian SDV

Bagian berikut menguraikan panduan dan praktik terbaik khusus untuk mengembangkan pengujian dalam Framework Pengujian SDV.

Penyiapan dan pembersihan

Kode penyiapan dan pembersihan harus berada di luar kasus pengujian. Metode teardown dipanggil meskipun pengujian gagal, untuk melakukan pembersihan perangkat yang tepat.

Lokasi kode penyiapan dan teardown bergantung pada kebutuhan spesifik pengujian, meskipun pengujian terganggu:

  1. Untuk menjalankan hanya sekali di awal dan akhir seluruh pengujian, gunakan setup_class dan teardown_class. Misalnya, dapatkan perangkat, tetapkan nilai variabel atau status yang tidak berubah di antara kasus pengujian, konfigurasi properti perangkat umum, atau tetapkan flag.
def setup_class(self):
  super().setup_class()
  # setup code

def teardown_class(self):
  # teardown code
  super().teardown_class()
  1. Untuk menjalankan di antara kasus pengujian, sebelum dan setelah setiap kasus pengujian. Misalnya, sesi interaktif atau eksekusi layanan umum.
def setup_test(self):
  super().setup_test()
  # setup code

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

Kasus pengujian dengan parameter

Gunakan kasus pengujian dengan parameter jika langkah-langkahnya sama di berbagai kasus pengujian untuk menghindari pengulangan kode.

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

Contoh ini membuat dua kasus pengujian test_name_ab dan test_name_cd.

Satu kasus pengujian untuk verifikasi perilaku

Kasus pengujian harus ringkas dan berfokus pada satu perilaku tertentu. Jika beberapa perilaku memiliki prasyarat atau langkah umum, pertimbangkan untuk memisahkannya. Anda dapat menggunakan setup_test atau parameterisasi untuk meminimalkan jumlah kode berulang.

Mengikuti pendekatan ini akan membuat pengujian lebih mudah dibaca dan di-debug karena menunjukkan dengan jelas langkah dan kondisi mana yang gagal.

Contoh
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()

Perilaku pengujian deterministik

Hindari menambahkan kondisional dalam pengujian yang mencabangkan perilakunya. Jika verifikasi perlu dibagi, gunakan dua kasus pengujian yang berbeda.

Jangan gunakan pengecualian

Pengujian dan helper umum harus menggunakan pernyataan, bukan pengecualian. Hal ini memfasilitasi proses debug dan mengikuti pola pengujian.

Contoh
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)
Contoh
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"
)

Jangan gunakan sleep

Hindari penggunaan sleep karena dapat meningkatkan waktu eksekusi uji dan menyebabkan ketidakstabilan.

Jika pengujian mengharuskan menunggu peristiwa atau verifikasi untuk dilanjutkan, gunakan Metode Menunggu yang disediakan dalam framework.

Gunakan metode menunggu dengan hati-hati karena eksekusi uji akan tetap diblokir hingga kondisi cocok atau waktu tunggu tercapai.

Jika Anda perlu menunggu kondisi selesai dalam pengujian, ajukan pertanyaan berikut:

  1. Berapa waktu tunggu yang wajar?

    Jika peristiwa diharapkan terjadi dalam jangka waktu tertentu, waktu tunggu harus sesuai dengan ekspektasi tersebut untuk memastikan pengujian gagal dengan cepat. Kurangi waktu tunggu jika perlu (default-nya adalah 30 detik).

  2. Seberapa mahal operasi yang dilakukan oleh metode menunggu?

    Hindari sering memanggil operasi yang mahal. Tingkatkan interval polling jika perlu (default-nya adalah 0,5 detik).

Kasus pengujian dengan persyaratan

Jika pengujian memiliki kasus pengujian dengan persyaratan eksplisit untuk berfungsi (misalnya, target tempat pengujian harus dijalankan), Anda dapat melewatinya jika tidak memenuhi persyaratan:

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