การเปิดตัวฟีเจอร์ Flag สำหรับการเปิดตัวฟีเจอร์ทำให้เกิดนโยบายการทดสอบใหม่ ที่คุณต้องปฏิบัติตาม ดังนี้
- การทดสอบต้องครอบคลุมทั้งลักษณะการทำงานที่เปิดใช้และปิดใช้ของ Flag
- คุณต้องใช้กลไกอย่างเป็นทางการเพื่อตั้งค่าสถานะระหว่างการทดสอบ
- การทดสอบ xTS ไม่ควรกําหนดค่าสถานะในการทดสอบใหม่
ส่วนถัดไปจะอธิบายกลไกอย่างเป็นทางการที่คุณต้องใช้เพื่อปฏิบัติตาม นโยบายเหล่านี้
ทดสอบโค้ดที่ถูกแจ้ง
| สถานการณ์การทดสอบ | กลไกที่ใช้ |
|---|---|
| การทดสอบในเครื่องเมื่อค่าสถานะเปลี่ยนแปลงบ่อย | Android Debug Bridge ตามที่อธิบายไว้ใน เปลี่ยนค่าของฟีเจอร์แฟลกขณะรันไทม์ |
| การทดสอบในเครื่องเมื่อค่าสถานะไม่เปลี่ยนแปลงบ่อย | ไฟล์ค่าแฟล็กตามที่อธิบายไว้ในตั้งค่าแฟล็กการเปิดตัวฟีเจอร์ |
| การทดสอบแบบครบวงจรที่ค่าของ Flag เปลี่ยนแปลง | FeatureFlagTargetPreparer ตามที่อธิบายไว้ในสร้างการทดสอบจากต้นทางถึงปลายทาง |
| การทดสอบหน่วยที่ค่าแฟล็กมีการเปลี่ยนแปลง | SetFlagsRule โดยมี @EnableFlags และ @DisableFlags ตามที่อธิบายไว้ในสร้างการทดสอบหน่วย (Java และ Kotlin) หรือ
สร้างการทดสอบหน่วย (C และ C++) |
| การทดสอบแบบครบวงจรหรือการทดสอบหน่วยที่ค่าสถานะเปลี่ยนแปลงไม่ได้ | CheckFlagsRule ตามที่อธิบายไว้ในสร้างการทดสอบแบบครบวงจรหรือการทดสอบหน่วยที่ค่าของ Flag ไม่เปลี่ยนแปลง |
สร้างการทดสอบแบบครบวงจร
AOSP มีคลาสที่ชื่อ FeatureFlagTargetPreparer ซึ่งช่วยให้คุณ
ทดสอบอุปกรณ์แบบครบวงจรได้ คลาสนี้ยอมรับการลบล้างค่าแฟล็กเป็น
อินพุต ตั้งค่าแฟล็กเหล่านั้นในการกำหนดค่าอุปกรณ์ก่อนการดำเนินการทดสอบ
และกู้คืนแฟล็กหลังการดำเนินการ
คุณสามารถใช้ฟังก์ชันของคลาส FeatureFlagTargetPreparer ได้ที่ระดับโมดูลทดสอบและการกำหนดค่าการทดสอบ
ใช้ FeatureFlagTargetPreparer ในการกำหนดค่าโมดูลทดสอบ
หากต้องการใช้ FeatureFlagTargetPreparer ในการกำหนดค่าโมดูลทดสอบ ให้ใส่
FeatureFlagTargetPreparer และการลบล้างค่าแฟล็กในAndroidTest.xml
ไฟล์การกำหนดค่าโมดูลทดสอบ
<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer">
<option name="flag-value"
value="permissions/com.android.permission.flags.device_aware_permission_grant=true"/>
<option name="flag-value"
value="virtual_devices/android.companion.virtual.flags.stream_permissions=true"/>
</target_preparer>
สถานที่:
target.preparer classจะตั้งค่าเป็นcom.android.tradefed.targetprep.FeatureFlagTargetPreparerเสมอoptionคือการลบล้างฟีเจอร์โดยตั้งค่าnameเป็นflag-valueและvalueเป็นnamespace/aconfigPackage.flagName=true|falseเสมอ
สร้างโมดูลทดสอบที่มีพารามิเตอร์ตามสถานะของฟีเจอร์แฟลก
วิธีสร้างโมดูลทดสอบที่มีพารามิเตอร์ตามสถานะของฟีเจอร์แฟลก
ใส่
FeatureFlagTargetPreparerในไฟล์การกำหนดค่าAndroidTest.xmlโมดูลทดสอบ<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >ระบุค่าแฟล็ก ตัวเลือกในส่วน
test_module_configของไฟล์บิลด์Android.bpดังนี้android_test { name: "MyTest" ... } test_module_config { name: "MyTestWithMyFlagEnabled", base: "MyTest", ... options: [ {name: "flag-value", value: "telephony/com.android.internal.telephony.flags.oem_enabled_satellite_flag=true"}, ], } test_module_config { name: "MyTestWithMyFlagDisabled", base: "MyTest", ... options: [ {name: "flag-value", value: "telephony/com.android.internal.telephony.flags.carrier_enabled_satellite_flag=true"}, ], }ฟิลด์
optionsมีการลบล้างค่าสถานะโดยตั้งค่าnameเป็นflag-valueและตั้งค่าvalueเป็นnamespace/aconfigPackage.flagName=true|falseเสมอ
สร้างการทดสอบหน่วย (Java และ Kotlin)
ส่วนนี้อธิบายแนวทางการลบล้างค่าแฟล็ก aconfig ที่ระดับคลาสและเมธอด (ต่อการทดสอบ) ในการทดสอบ Java และ Kotlin
หากต้องการเขียน Unit Test อัตโนมัติในโค้ดเบสขนาดใหญ่ที่มี Flag จำนวนมาก ให้ทำตามขั้นตอนต่อไปนี้
- ใช้คลาส
SetFlagsRuleกับคำอธิบายประกอบ@EnableFlagsและ@DisableFlagsเพื่อทดสอบโค้ดทุกสาขา - ใช้เมธอด
SetFlagsRule.ClassRuleเพื่อหลีกเลี่ยงข้อบกพร่องในการทดสอบที่พบบ่อย - ใช้
FlagsParameterizationเพื่อทดสอบคลาสในชุดการกำหนดค่าฟีเจอร์แฟล็กที่หลากหลาย
ทดสอบโค้ดทุกสาขา
สำหรับโปรเจ็กต์ที่ใช้คลาสแบบคงที่เพื่อเข้าถึงฟีเจอร์
SetFlagsRule ระบบจะจัดเตรียมคลาสตัวช่วยเพื่อลบล้างค่าฟีเจอร์ ข้อมูลโค้ดต่อไปนี้
แสดงวิธีรวม SetFlagsRule และเปิดใช้หลายๆ แฟล็กพร้อมกัน
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.example.android.aconfig.demo.flags.Flags;
...
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Test
@EnableFlags({Flags.FLAG_FLAG_FOO, Flags.FLAG_FLAG_BAR})
public void test_flag_foo_and_flag_bar_turned_on() {
...
}
สถานที่:
@Ruleคือคำอธิบายประกอบที่ใช้เพื่อเพิ่มทรัพยากร Dependency ของ flag-JUnit ของคลาสSetFlagsRuleSetFlagsRuleคือคลาสตัวช่วยที่ใช้ในการลบล้างค่าสถานะ ดูข้อมูลเกี่ยวกับวิธีที่SetFlagsRuleกําหนดค่าเริ่มต้นได้ที่ค่าเริ่มต้นของอุปกรณ์@EnableFlagsคือคำอธิบายประกอบที่ยอมรับชื่อฟีเจอร์ จำนวนเท่าใดก็ได้ เมื่อปิดใช้ฟีเจอร์ทดลอง ให้ใช้@DisableFlagsคุณใช้ คำอธิบายประกอบ เหล่านี้กับเมธอดหรือคลาสก็ได้
ตั้งค่าแฟล็กสำหรับกระบวนการทดสอบทั้งหมด โดยเริ่มจาก
SetFlagsRule ซึ่งอยู่ก่อนวิธีการตั้งค่าที่ใส่คำอธิบายประกอบ @Before
ในการทดสอบ ค่าสถานะจะกลับไปเป็นสถานะก่อนหน้าเมื่อ
SetFlagsRule เสร็จสิ้น ซึ่งจะเกิดขึ้นหลังจากวิธีการตั้งค่าที่ใส่คำอธิบายประกอบ @After
ตรวจสอบว่าได้ตั้งค่าสถานะอย่างถูกต้อง
ดังที่กล่าวไว้ก่อนหน้านี้ SetFlagsRule ใช้กับคำอธิบายประกอบ @Rule
JUnit ซึ่งหมายความว่า
SetFlagsRule ไม่สามารถรับประกันว่ามีการตั้งค่าฟีเจอร์แฟลกอย่างถูกต้องในระหว่างตัวสร้างของคลาสทดสอบ หรือวิธีการใดๆ ที่มีคำอธิบายประกอบ @BeforeClass หรือ @AfterClass
หากต้องการให้มั่นใจว่ามีการสร้างการทดสอบด้วยค่าคลาสที่ถูกต้อง ให้ใช้เมธอด SetFlagsRule.ClassRule เพื่อให้ระบบไม่สร้างการทดสอบจนกว่าจะมีการตั้งค่าเมธอดที่ทำเครื่องหมายด้วย @Before
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.example.android.aconfig.demo.flags.Flags;
class ExampleTest {
@ClassRule public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
@Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
private DemoClass underTest = new DemoClass();
@Test
@EnableFlags(Flags.FLAG_FLAG_FOO)
public void test_flag_foo_turned_on() {
...
}
}
การเพิ่มSetFlagsRule.ClassRule class rule test_flag_foo_turned_on
จะล้มเหลวก่อนเรียกใช้เมื่อตัวสร้างของ DemoClass อ่าน FLAG_FLAG_FOO
หากทั้งชั้นเรียนต้องเปิดใช้ Flag ให้ย้าย@EnableFlagsคำอธิบายประกอบไปที่
ระดับชั้นเรียน (ก่อนการประกาศชั้นเรียน) การย้ายคำอธิบายประกอบไปที่ระดับคลาสช่วยให้ SetFlagsRule.ClassRule มั่นใจได้ว่ามีการตั้งค่าสถานะอย่างถูกต้อง
ในระหว่างตัวสร้างของคลาสทดสอบ หรือในระหว่างเมธอดที่ใช้คำอธิบายประกอบ @BeforeClass หรือ
@AfterClass
เรียกใช้การทดสอบในการกำหนดค่าฟีเจอร์หลายรายการ
เนื่องจากคุณตั้งค่าสถานะได้ตามการทดสอบแต่ละครั้ง คุณจึงใช้การกำหนดพารามิเตอร์เพื่อเรียกใช้การทดสอบในการกำหนดค่าสถานะหลายรายการได้ด้วย
...
import com.example.android.aconfig.demo.flags.Flags;
...
@RunWith(ParameterizedAndroidJunit4::class)
class FooBarTest {
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
return FlagsParameterization.allCombinationsOf(Flags.FLAG_FOO, Flags.FLAG_BAR);
}
@Rule
public SetFlagsRule mSetFlagsRule;
public FooBarTest(FlagsParameterization flags) {
mSetFlagsRule = new SetFlagsRule(flags);
}
@Test public void fooLogic() {...}
@DisableFlags(Flags.FLAG_BAR)
@Test public void legacyBarLogic() {...}
@EnableFlags(Flags.FLAG_BAR)
@Test public void newBarLogic() {...}
}
โปรดทราบว่าเมื่อใช้ SetFlagsRule แต่ไม่มีการกำหนดพารามิเตอร์ คลาสนี้จะเรียกใช้การทดสอบ 3 รายการ (fooLogic, legacyBarLogic และ newBarLogic) เมธอด fooLogic จะทำงานกับค่าของ FLAG_FOO และ FLAG_BAR ที่ตั้งค่าไว้ในอุปกรณ์
เมื่อเพิ่มการกำหนดพารามิเตอร์แล้ว FlagsParameterization.allCombinationsOf
เมธอดจะสร้างชุดค่าผสมที่เป็นไปได้ทั้งหมดของแฟล็ก FLAG_FOO และ FLAG_BAR ดังนี้
FLAG_FOOคือtrueและFLAG_BARคือtrueFLAG_FOOคือtrueและFLAG_BARคือfalseFLAG_FOOคือfalseและFLAG_BARคือtrueFLAG_FOOเป็นเท็จและFLAG_BARเป็นfalse
แทนที่จะเปลี่ยนค่าสถานะโดยตรง คำอธิบายประกอบ @DisableFlags และ
@EnableFlags จะแก้ไขค่าสถานะตามเงื่อนไขของพารามิเตอร์ ตัวอย่างเช่น legacyBarLogic จะทํางานเมื่อปิดใช้ FLAG_BAR เท่านั้น ซึ่งจะเกิดขึ้นใน
การผสมผสานของ 2 ใน 4 ของฟีเจอร์ ระบบจะข้าม legacyBarLogic สำหรับการผสมผสานอีก 2 รายการ
การสร้างพารามิเตอร์สำหรับฟีเจอร์แฟล็กทำได้ 2 วิธี ดังนี้
FlagsParameterization.allCombinationsOf(String...)จะดำเนินการทดสอบแต่ละรายการ 2^n ครั้ง เช่น แฟล็ก 1 รายการจะเรียกใช้การทดสอบ 2 เท่า หรือแฟล็ก 4 รายการจะเรียกใช้การทดสอบ 16 เท่าFlagsParameterization.progressionOf(String...)จะเรียกใช้การทดสอบแต่ละรายการ n+1 ครั้ง เช่น แฟล็ก 1 รายการจะเรียกใช้การทดสอบ 2 รายการ และแฟล็ก 4 รายการจะเรียกใช้แฟล็ก 5 รายการ
สร้างการทดสอบหน่วย (C และ C++)
AOSP มีมาโครค่าแฟล็กสำหรับเทสต์ C และ C++ ที่เขียนในเฟรมเวิร์ก GoogleTest
ในแหล่งที่มาของการทดสอบ ให้รวมคำจำกัดความของมาโครและไลบรารีที่สร้างโดย aconfig ดังนี้
#include <flag_macros.h> #include "android_cts_flags.h"ในแหล่งข้อมูลทดสอบ ให้ใช้
TEST_WITH_FLAGSและTEST_F_WITH_FLAGSแทนมาโครTESTและTESTFสำหรับกรณีทดสอบ#define TEST_NS android::cts::flags::tests ... TEST_F_WITH_FLAGS( TestFWithFlagsTest, requies_disabled_flag_enabled_skip, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(TEST_NS, readwrite_enabled_flag)) ) { TestFail(); } ... TEST_F_WITH_FLAGS( TestFWithFlagsTest, multi_flags_for_same_state_skip, REQUIRES_FLAGS_ENABLED( ACONFIG_FLAG(TEST_NS, readwrite_enabled_flag), LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag) ) ) { TestFail(); } ... TEST_WITH_FLAGS( TestWithFlagsTest, requies_disabled_flag_enabled_skip, REQUIRES_FLAGS_DISABLED( LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_enabled_flag)) ) { FAIL(); } ... TEST_WITH_FLAGS( TestWithFlagsTest, requies_enabled_flag_enabled_executed, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_NS, readwrite_enabled_flag)) ) { TestWithFlagsTestHelper::executed_tests.insert( "requies_enabled_flag_enabled_executed"); }สถานที่:
- ใช้มาโคร
TEST_WITH_FLAGSและTEST_F_WITH_FLAGSแทน มาโครTESTและTEST_F REQUIRES_FLAGS_ENABLEDกำหนดชุดค่าสถานะการเปิดตัวฟีเจอร์ที่ต้องเป็นไปตามเงื่อนไขที่เปิดใช้ คุณเขียนแฟล็กเหล่านี้ในมาโครACONFIG_FLAGหรือLEGACY_FLAGได้REQUIRES_FLAGS_DISABLEDกำหนดชุดฟีเจอร์แฟล็กที่ต้องเป็นไปตามเงื่อนไข ที่ปิดใช้ คุณเขียนแฟล็กเหล่านี้ในมาโครACONFIG_FLAGหรือLEGACY_FLAGได้ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag)คือมาโครที่ใช้สำหรับแฟล็ก ที่กำหนดไว้ในไฟล์การกำหนดค่า มาโครนี้ยอมรับเนมสเปซ (TEST_NS) และชื่อฟีเจอร์แฟลก (readwrite_enabled_flag)LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag)เป็น มาโครที่ใช้สำหรับค่าสถานะที่ตั้งค่าไว้ในการกำหนดค่าอุปกรณ์โดยค่าเริ่มต้น
- ใช้มาโคร
ใน
Android.bpไฟล์บิลด์ ให้เพิ่มไลบรารีที่สร้างโดย aconfig และ ไลบรารีมาโครที่เกี่ยวข้องเป็นทรัพยากร Dependency ของการทดสอบcc_test { name: "FlagMacrosTests", srcs: ["src/FlagMacrosTests.cpp"], static_libs: [ "libgtest", "libflagtest", "my_aconfig_lib", ], shared_libs: [ "libbase", "server_configurable_flags", ], test_suites: ["general-tests"], ... }เรียกใช้การทดสอบในเครื่องด้วยคำสั่งนี้
atest FlagMacrosTestsหากปิดใช้ฟีเจอร์
my_namespace.android.myflag.tests.my_flagผลการทดสอบจะเป็นดังนี้[1/2] MyTest#test1: IGNORED (0ms) [2/2] MyTestF#test2: PASSED (0ms)หากเปิดใช้ฟีเจอร์ทดลอง
my_namespace.android.myflag.tests.my_flagผลการทดสอบจะเป็นดังนี้[1/2] MyTest#test1: PASSED (0ms) [2/2] MyTestF#test2: IGNORED (0ms)
สร้างการทดสอบแบบครบวงจรหรือการทดสอบหน่วยในกรณีที่ค่าของฟีเจอร์แฟล็กไม่เปลี่ยนแปลง
สำหรับกรณีทดสอบที่คุณไม่สามารถลบล้างค่าสถานะและกรองการทดสอบได้เฉพาะในกรณีที่
อิงตามสถานะค่าสถานะปัจจุบัน ให้ใช้กฎ CheckFlagsRule ที่มี
คำอธิบายประกอบ RequiresFlagsEnabled และ RequiresFlagsDisabled
ขั้นตอนต่อไปนี้แสดงวิธีสร้างและเรียกใช้การทดสอบแบบครบวงจรหรือการทดสอบหน่วย ซึ่งไม่สามารถลบล้างค่าสถานะได้
ในโค้ดทดสอบ ให้ใช้
CheckFlagsRuleเพื่อใช้การกรองการทดสอบ นอกจากนี้ ให้ใช้คำอธิบายประกอบ JavaRequiresFlagsEnabledและRequiredFlagsDisabledเพื่อระบุข้อกำหนดของฟีเจอร์แฟล็กสำหรับการทดสอบการทดสอบฝั่งอุปกรณ์ใช้คลาส
DeviceFlagsValueProviderดังนี้@RunWith(JUnit4.class) public final class FlagAnnotationTest { @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Test @RequiresFlagsEnabled(Flags.FLAG_FLAG_NAME_1) public void test1() {} @Test @RequiresFlagsDisabled(Flags.FLAG_FLAG_NAME_1) public void test2() {} }การทดสอบฝั่งโฮสต์ใช้คลาส
HostFlagsValueProvider@RunWith(DeviceJUnit4ClassRunner.class) public final class FlagAnnotationTest extends BaseHostJUnit4Test { @Rule public final CheckFlagsRule mCheckFlagsRule = HostFlagsValueProvider.createCheckFlagsRule(this::getDevice); @Test @RequiresFlagsEnabled(Flags.FLAG_FLAG_NAME_1) public void test1() {} @Test @RequiresFlagsDisabled(Flags.FLAG_FLAG_NAME_1) public void test2() {} }เพิ่ม
jflag-unitและไลบรารีที่สร้างโดย aconfig ลงในส่วนstatic_libsของไฟล์บิลด์สำหรับการทดสอบandroid_test { name: "FlagAnnotationTests", srcs: ["*.java"], static_libs: [ "androidx.test.rules", "my_aconfig_lib", "flag-junit", "platform-test-annotations", ], test_suites: ["general-tests"], }ใช้คำสั่งต่อไปนี้เพื่อเรียกใช้การทดสอบในเครื่อง
atest FlagAnnotationTestsหากปิดใช้ฟีเจอร์
Flags.FLAG_FLAG_NAME_1ผลการทดสอบจะเป็นดังนี้[1/2] com.cts.flags.FlagAnnotationTest#test1: ASSUMPTION_FAILED (10ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: PASSED (2ms)มิเช่นนั้น ผลการทดสอบจะเป็นดังนี้
[1/2] com.cts.flags.FlagAnnotationTest#test1: PASSED (2ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: ASSUMPTION_FAILED (10ms)
ค่าเริ่มต้นของอุปกรณ์
SetFlagsRule ที่เริ่มต้นใช้ค่าสถานะจากอุปกรณ์ หากไม่ได้ลบล้างค่าแฟล็กในอุปกรณ์ เช่น ด้วย adb ค่าเริ่มต้น
จะเหมือนกับ
การกำหนดค่ารุ่นของบิลด์ หากค่าในอุปกรณ์ถูก
ลบล้าง SetFlagsRule จะใช้ค่าที่ลบล้างเป็นค่า
เริ่มต้น
หากมีการดำเนินการทดสอบเดียวกันภายใต้การกำหนดค่าการเผยแพร่ที่แตกต่างกัน ค่าของฟีเจอร์แฟลกที่ไม่ได้ตั้งค่าอย่างชัดเจนด้วย SetFlagsRule อาจแตกต่างกัน
หลังจากการทดสอบแต่ละครั้ง SetFlagsRule จะคืนค่าอินสแตนซ์ FeatureFlags ใน Flags
เป็น FeatureFlagsImpl เดิม เพื่อไม่ให้ส่งผลกระทบต่อ
เมธอดและคลาสการทดสอบอื่นๆ