系統測試是指使用 SDV 測試架構建立的任何 SDV 測試。
建立測試
測試位置
<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
測試檔案
README.md:所有測試都必須包含測試目的和執行方式的說明。測試檔案:所有測試都遵循類似的結構:
"""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()
- 建構檔案:
Android.bp。檔案結構如下:
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>",
}
命名慣例
為識別及找出不同類型的測試,建立測試時必須遵循特定命名慣例:
- 測試範例:
- 檔案名稱:
sdv_sample_<NAME>_test.py - 類別名稱:
SdvSampleNameTest
- 檔案名稱:
- E2E 測試:
- 檔案名稱:
sdv_e2e_<NAME>_test.py - 類別名稱:
SdvE2ENameTest
- 檔案名稱:
- 長時間執行的測試:
- 檔案名稱:
sdv_long_running_<NAME>_test.py - 類別名稱:
SdvLongRunningNameTest
- 檔案名稱:
- 效能測試:
- 檔案名稱:
sdv_performance_<NAME>_test.py - 類別名稱:
SdvPerformanceNameTest
- 檔案名稱:
- 硬體測試:
- 檔案名稱:
sdv_hw_<NAME>_test.py - 類別名稱:
SdvHWNameTest
- 檔案名稱:
程式碼指南
本節提供編寫 SDV 系統測試的指南和最佳做法。
Python 和 Mobly
請熟悉 Python 樣式指南和 Mobly 最佳做法,並考量下列 SDV 專屬建議:
除了斷言之外,請避免直接使用 Mobly 匯入。SDV 測試架構則以此為基礎,並著重於 SDV。
斷言:直接使用 Mobly 斷言。
SDV 測試
下列各節說明在 SDV 測試架構中開發測試的具體指南和最佳做法。
設定和清除
設定和清除程式碼必須位於測試案例之外。即使測試失敗,系統仍會呼叫拆解方法,以便正確清理裝置。
設定和拆解程式碼的位置取決於測試的特定需求,即使測試中斷也一樣:
- 如要在整個測試的開頭和結尾只執行一次,請使用
setup_class和teardown_class。例如取得裝置、設定測試案例之間不會變更的變數值或狀態、設定常見裝置屬性,或設定旗標。
def setup_class(self):
super().setup_class()
# setup code
def teardown_class(self):
# teardown code
super().teardown_class()
- 在測試案例之間執行,也就是在每個測試案例前後執行。例如互動式工作階段或一般服務執行。
def setup_test(self):
super().setup_test()
# setup code
def teardown_test(self):
# teardown code
super().teardown_test()
參數化測試案例
如果不同測試案例的步驟相同,請使用參數化測試案例,避免程式碼重複。
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
這個範例會建立兩個測試案例:test_name_ab 和 test_name_cd。
一個用於驗證行為的測試案例
測試案例應精簡,並著重於一項特定行為。如果多個行為共用相同的前提條件或步驟,建議您將其拆分。您可以使用 setup_test 或參數化,盡量減少重複的程式碼。
採用這種做法,測試會更容易閱讀和偵錯,因為它會清楚指出哪些步驟和條件失敗。
範例
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()
確定性測試行為
避免在測試中新增條件,以免分支行為。如果需要拆分驗證,請改用兩個不同的測試案例。
不使用例外狀況
測試和常見輔助程式必須使用斷言,而非例外狀況。這有助於偵錯,並遵循測試模式。
範例
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)
範例
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,因為這會增加測試執行時間,並導致不穩定。
如果測試需要等待事件或驗證才能繼續,請改用架構提供的等待方法。
請謹慎使用等待方法,因為測試執行作業會保持封鎖狀態,直到條件相符或逾時為止。
當您需要在測試中等待條件完成時,請提出下列問題:
合理的逾時時間為何?
如果預期事件會在特定時間範圍內發生,逾時時間應與預期時間相符,確保測試能快速失敗。如有需要,請縮短逾時時間 (預設為 30 秒)。
等待方法執行的作業會耗用多少資源?
避免頻繁呼叫耗費資源的作業。如有需要,請增加輪詢間隔 (預設為 0.5 秒)。
測試案例與需求
如果測試包含有明確執行需求的測試案例 (例如應執行的目標),您可以在不符合需求時略過這些案例:
def test_with_requirement(self):
self.get_test_validator().skip_if(expr, reason)
# Test case