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 testlerde testin amacı ve nasıl çalıştırılacağı açıklanmalıdır.

  • Test dosyası: Tüm testler benzer bir yapıyı izler:

"""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ı şu şekildedir:
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 belirlemek 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

E2E Testi

  • Dosya adı: sdv_e2e_<NAME>_test.py

  • Sınıf adı: SdvE2ENameTest

Uzun Süren 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 Yönergeleri

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 en iyi uygulamaları hakkında bilgi edinin. Ayrıca, SDV'ye özel aşağıdaki önerileri göz önünde bulundurun:

  • Onaylamalar dışında Mobly içe aktarmalarını doğrudan kullanmaktan kaçının. SDV Test Çerçevesi, SDV'ye odaklanarak bu temeli geliştirir.

  • Onaylamalar: Mobly onaylamalarını doğrudan kullanın.

SDV Testleri

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

Kurulum ve Temizleme

Kurulum ve temizleme kodu test senaryolarının dışında olmalıdır. Uygun cihaz temizliği için test başarısız olsa bile sökme 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. Tüm testin başında ve sonunda yalnızca bir kez çalıştırmak için setup_class ve teardown_class kullanın. Örneğin, cihazları alma, test senaryoları arasında değişmeyen değişken değerleri veya durumları 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. Her birinden önce ve sonra olmak üzere test senaryoları arasında çalıştırmak için. Örneğin, etkileşimli bir 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()

Parametre haline getirilmiş test durumları

Kod tekrarını önlemek için adımlar farklı test senaryolarında ortak olduğunda parametreli test senaryoları 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 test_name_ab ve test_name_cd olmak üzere iki test senaryosu oluşturulur.

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

Test senaryoları kısa ve öz 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üşünebilirsiniz. Tekrarlanan kod miktarını en aza indirmek için setup_test veya parametrelendirme kullanabilirsiniz.

Bu yaklaşımı izlediğinizde, hangi adımların ve koşulların başarısız olduğu net bir şekilde belirtildiğinden testlerin okunması ve hatalarının ayıklanması kolaylaşır.

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

Belirleyici test davranışı

Teste davranışını dallandıran koşullar eklemekten kaçının. Doğrulamanın bölünmesi gerekiyorsa bunun yerine iki farklı test durumu kullanın.

İstisnaları kullanmayın

Testler ve yaygın yardımcılar, istisnalar yerine onaylamaları kullanmalıdır. Bu sayede hata ayıklama kolaylaşır ve test kalıpları izlenir.

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

sleep() kullanmayın

Test yürütme süresini artırdığı ve kararsızlığa neden olduğu için sleep() kullanmaktan kaçının.

Testin devam etmesi için bir etkinlik veya doğrulama beklenmesi gerektiğinde, bunun yerine çerçevede sağlanan bekleme yöntemlerini kullanın.

Koşul eşleşene veya zaman aşımı süresi dolana kadar test işlemi engellenmeye devam edeceğinden, bekleme yöntemlerini dikkatli kullanın.

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

  1. Makul bir zaman aşımı nedir?

    Belirli bir zaman aralığında bir etkinlik bekleniyorsa testin hızlı bir şekilde başarısız olmasını sağlamak için zaman aşımı bu beklentiyle eşleşmelidir. Gerekirse zaman aşımını azaltın (varsayılan değer 30 saniyedir).

  2. Bekleme yöntemi tarafından gerçekleştirilen işlem ne kadar maliyetli?

    Pahalı 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).

Gereksinim içeren test durumları

Çalışmak için açık koşulları olan test senaryoları (ör. çalışması gereken hedef) varsa koşullara uymayanları atlayabilirsiniz:

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