SDV sistem testi oluşturma

Sistem testleri, SDV Test Çerçevesi kullanılarak oluşturulan tüm SDV testlerini ifade eder.

Test oluşturma

Test konumu

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

Dosyaları test etme

  • README.md: Tüm testler, testin amacının ve nasıl çalıştırılacağının açıklamasını içermelidir.

  • Test dosyası: Tüm testler benzer bir yapıya sahiptir:

"""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()
  • Derleme dosyası: Android.bp. Dosya yapısı aşağıdaki gibidir:
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>",
}

Adlandırma kuralı

Farklı test türlerini tanımlamak ve bulmak için testler belirli bir adlandırma kuralına göre oluşturulmalıdır:

  • Örnek test:
    • Dosya adı: sdv_sample_<NAME>_test.py
    • Sınıf adı: SdvSampleNameTest
  • Uçtan uca test:
    • Dosya adı: sdv_e2e_<NAME>_test.py
    • Sınıf adı: SdvE2ENameTest
  • Uzun süreli test:
    • Dosya adı: sdv_long_running_<NAME>_test.py
    • Sınıf adı: SdvLongRunningNameTest
  • Performans testi:
    • Dosya adı: sdv_performance_<NAME>_test.py
    • Sınıf adı: SdvPerformanceNameTest
  • Donanım testi:
    • Dosya adı: sdv_hw_<NAME>_test.py
    • Sınıf adı: SdvHWNameTest

Kod kuralları

Bu bölümde, SDV sistem testleri yazmayla ilgili yönergeler ve en iyi uygulamalar yer almaktadır.

Python ve Mobly

Python stil kılavuzu ve Mobly ile ilgili en iyi uygulamalar hakkında bilgi edinin ve SDV'ye özel aşağıdaki önerileri göz önünde bulundurun:

  • Onaylar dışında Mobly içe aktarma işlemlerini doğrudan kullanmaktan kaçının. SDV Test Çerçevesi, SDV'ye odaklanarak bu çerçeveyi temel alır.

  • Onaylar: Mobly onaylarını doğrudan kullanın.

SDV testleri

Aşağıdaki bölümlerde, SDV Test Çerçevesi'nde test geliştirme ile ilgili özel yönergeler ve en iyi uygulamalar açıklanmaktadır.

Kurulum ve temizleme

Kurulum ve temizleme kodu, test durumlarının dışında olmalıdır. Test başarısız olsa bile cihazın düzgün bir şekilde temizlenmesi için kaldırma yöntemleri çağrılır.

Kurulum ve sökme kodunun konumu, test kesintiye uğrasa bile testin özel ihtiyaçlarına bağlıdır:

  1. Yalnızca testin başında ve sonunda bir kez çalıştırmak için setup_class ve teardown_class kullanın. Örneğin, cihazları alma, değişken değerlerini veya test durumları arasında değişmeyen durumu ayarlama, ortak cihaz özelliklerini yapılandırma ya da işaretleri ayarlama.
def setup_class(self):
  super().setup_class()
  # setup code

def teardown_class(self):
  # teardown code
  super().teardown_class()
  1. Test durumları arasında, her birinden önce ve sonra çalıştırılır. Örneğin, etkileşimli oturum veya ortak hizmet yürütme.
def setup_test(self):
  super().setup_test()
  # setup code

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

Parametreli test durumları

Kod tekrarını önlemek için adımlar farklı test durumlarında ortak olduğunda parametreleştirilmiş test durumlarını kullanın.

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

Örnekte iki test durumu (test_name_ab ve test_name_cd) oluşturulur.

Davranış doğrulaması için bir test durumu

Test durumları kısa olmalı ve belirli bir davranışa odaklanmalıdır. Birden fazla davranış ortak ön koşulları veya adımları paylaşıyorsa bunları bölmeyi düşünün. Tekrarlanan kod miktarını en aza indirmek için setup_test veya parametreleştirmeyi kullanabilirsiniz.

Bu yaklaşımı izlemek, hangi adımların ve koşulların başarısız olduğunu açıkça gösterdiği için testlerin okunmasını ve hata ayıklamasını kolaylaştırır.

Örnek
def test_verify_process(self):
  self.device.start_process()

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

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

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

  self.device.kill_process()
def setup_test(self):
  super().setup_test()
  self.device.start_process()

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

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

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

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

Deterministik test davranışı

Teste, davranışını dallara ayıran koşullar eklemekten kaçının. Bir doğrulamanın bölünmesi gerekiyorsa bunun yerine iki farklı test durumu kullanın.

İstisnaları kullanmama

Testler ve yaygın yardımcılar, istisnalar yerine onaylamaları kullanmalıdır. Bu, hata ayıklamayı kolaylaştırır ve test kalıplarına uyar.

Örnek
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)
Örnek
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"
)

Uyku modunu kullanma

Test işlemi süresini artırdığı ve tutarsızlığa neden olduğu için sleep kullanmaktan kaçının.

Testin devam etmesi için bir etkinliğin veya doğrulamanın beklenmesi gerektiğinde çerçevede sağlanan bekleme yöntemlerini kullanın.

Test işlemi, koşul karşılanana veya zaman aşımı süresi dolana kadar engellenmiş olarak kalacağından bekleme yöntemlerini dikkatli kullanın.

Bir testte bir koşulun tamamlanmasını beklemeniz gerektiğinde aşağıdaki soruları sorun:

  1. Makul bir zaman aşımı süresi ne kadardır?

    Bir etkinliğin belirli bir zaman aralığında gerçekleşmesi bekleniyorsa testin hızlı bir şekilde başarısız olması için zaman aşımı bu beklentiyle eşleşmelidir. Gerekirse zaman aşımı süresini azaltın (varsayılan değer 30 saniyedir).

  2. Bekleme yönteminin gerçekleştirdiği işlem ne kadar maliyetli?

    Yüksek maliyetli işlemleri sık sık çağırmaktan kaçının. Gerekirse yoklama aralığını artırın (varsayılan değer 0,5 saniyedir).

Gereksinimleri olan test durumları

Bir testte, çalışması için açık şartları olan test durumları varsa (örneğin, çalışması gereken hedef) şartları karşılamayan test durumlarını atlayabilirsiniz:

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