การใช้ Flag การเปิดตัวฟีเจอร์ทำให้เรามีนโยบายการทดสอบใหม่ซึ่งคุณต้องปฏิบัติตาม ดังนี้
- การทดสอบต้องครอบคลุมทั้งลักษณะการทำงานที่เปิดใช้และปิดใช้ของ Flag
- คุณต้องใช้กลไกอย่างเป็นทางการในการตั้งค่า Flag ระหว่างการทดสอบ
- การทดสอบ xTS ไม่ควรลบล้างค่า Flag ในการทดสอบ
ส่วนถัดไปจะอธิบายกลไกอย่างเป็นทางการที่คุณต้องใช้เพื่อปฏิบัติตามนโยบายเหล่านี้
ทดสอบโค้ดที่ได้รับแจ้ง
สถานการณ์การทดสอบ | กลไกที่ใช้ |
---|---|
การทดสอบภายในเมื่อค่า Flag เปลี่ยนแปลงบ่อย | บริดจ์แก้ไขข้อบกพร่องของ Android ตามที่อธิบายไว้ในหัวข้อเปลี่ยนค่าของ Flag ขณะรันไทม์ |
การทดสอบในเครื่องเมื่อค่า Flag ไม่มีการเปลี่ยนแปลงบ่อย | ไฟล์ค่า Flag ตามที่อธิบายไว้ในตั้งค่าค่า Flag การเปิดตัวฟีเจอร์ |
การทดสอบแบบเอนด์ทูเอนด์ที่มีการเปลี่ยนแปลงค่า Flag | FeatureFlagTargetPreparer ตามที่กล่าวไว้ในสร้างการทดสอบตั้งแต่ต้นจนจบ |
การทดสอบ 1 หน่วยที่ค่า Flag เปลี่ยนแปลง | SetFlagsRule กับ @EnableFlags และ @DisableFlags ตามที่พูดคุยกันในหัวข้อสร้างการทดสอบ 1 หน่วย (Java และ Kotlin) หรือ
สร้างการทดสอบ 1 หน่วย (C และ C++) |
การทดสอบแบบเอนด์ทูเอนด์หรือยูนิตที่ค่า Flag เปลี่ยนแปลงไม่ได้ | CheckFlagsRule ตามที่กล่าวไว้ในสร้างการทดสอบแบบจุดต่อจุดหรือแบบ 1 หน่วยที่ค่า Flag ไม่เปลี่ยนแปลง |
สร้างการทดสอบตั้งแต่ต้นจนจบ
AOSP มีคลาสชื่อ FeatureFlagTargetPreparer
ซึ่งเปิดใช้การทดสอบจากต้นทางถึงปลายทางในอุปกรณ์ คลาสนี้ยอมรับการลบล้างค่า Flag เป็นอินพุต ตั้งค่า Flag ดังกล่าวในการกำหนดค่าอุปกรณ์ก่อนการดำเนินการทดสอบ และคืนค่า Flag หลังการดำเนินการ
คุณจะใช้ฟังก์ชันการทำงานของคลาส FeatureFlagTargetPreparer
ที่โมดูลการทดสอบและระดับการกำหนดค่าการทดสอบได้
ใช้ FeatureFlagTargetPreparer ในการกำหนดค่าโมดูลทดสอบ
หากต้องการใช้ FeatureFlagTargetPreparer
ในการกำหนดค่าโมดูลทดสอบ ให้ใส่ FeatureFlagTargetPreparer
และการลบล้างค่า Flag ในไฟล์การกำหนดค่าโมดูลทดสอบ 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
สร้างการทดสอบ 1 หน่วย (Java และ Kotlin)
ส่วนนี้อธิบายวิธีการลบล้างค่า Flag aconfig ที่ระดับคลาสและเมธอด (ต่อการทดสอบ) ในการทดสอบ Java และ Kotlin
หากต้องการเขียนการทดสอบหน่วยอัตโนมัติในฐานของโค้ดขนาดใหญ่ที่มี Flag จำนวนมาก ให้ทำตามขั้นตอนต่อไปนี้
- ใช้คลาส
SetFlagsRule
ที่มีคำอธิบายประกอบ@EnableFlags
และ@DisableFlags
เพื่อทดสอบสาขาโค้ดทั้งหมด - ใช้เมธอด
SetFlagsRule.ClassRule
เพื่อหลีกเลี่ยงข้อบกพร่องการทดสอบที่พบบ่อย - ใช้
FlagsParameterization
เพื่อทดสอบชั้นเรียนที่มีชุดการกำหนดค่า Flag ต่างๆ ได้อย่างหลากหลาย
ทดสอบสาขาโค้ดทั้งหมด
สําหรับโปรเจ็กต์ที่ใช้คลาสแบบคงที่เพื่อเข้าถึง Flag ระบบจะมีคลาสตัวช่วย SetFlagsRule
ไว้ใช้ลบล้างค่า Flag ข้อมูลโค้ดต่อไปนี้แสดงวิธีรวม 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
คือแอตทริบิวต์ที่ใช้เพื่อเพิ่มการพึ่งพา Flag-JUnit ของคลาสSetFlagsRule
SetFlagsRule
คือคลาสตัวช่วยที่ระบุไว้เพื่อลบล้างค่า Flag ดูข้อมูลเกี่ยวกับวิธีที่SetFlagsRule
กำหนดค่าเริ่มต้นได้ที่ค่าเริ่มต้นของอุปกรณ์@EnableFlags
เป็นคำอธิบายประกอบที่ยอมรับจำนวนชื่อ Flag ที่กำหนดเอง เมื่อปิดใช้การตั้งค่าสถานะ ให้ใช้@DisableFlags
คุณสามารถใช้คำอธิบายประกอบ กับเมธอดหรือชั้นเรียนก็ได้
กำหนดค่าแฟล็กสำหรับกระบวนการทดสอบทั้งหมด โดยเริ่มต้นด้วย SetFlagsRule
ซึ่งอยู่ก่อนวิธีการตั้งค่าที่มีคำอธิบายประกอบ @Before
ในการทดสอบ ค่าแฟล็กจะเปลี่ยนกลับเป็นสถานะก่อนหน้าเมื่อ SetFlagsRule
เสร็จสิ้น ซึ่งอยู่หลังจากวิธีการตั้งค่าที่มีคำอธิบายประกอบ @After
ตรวจสอบว่าได้ตั้งค่า Flag อย่างถูกต้อง
ดังที่ได้กล่าวไว้ก่อนหน้านี้ SetFlagsRule
ใช้กับคำอธิบายประกอบ @Rule
ของ JUnit ซึ่งหมายความว่า SetFlagsRule
ไม่สามารถรับประกันได้ว่าการตั้งค่า Flag ถูกต้องในระหว่างการสร้างคอนสตรัคเตอร์ของคลาสทดสอบ หรือเมธอดที่มีคำอธิบายประกอบ @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
ทำให้ test_flag_foo_turned_on
ทำงานไม่สำเร็จก่อนที่จะรันเมื่อตัวสร้างของ DemoClass
อ่าน FLAG_FLAG_FOO
หากต้องเปิดใช้ Flag กับทั้งคลาส ให้ย้ายคำอธิบายประกอบ @EnableFlags
ไปที่ระดับคลาส (ก่อนการประกาศคลาส) การย้ายคำอธิบายประกอบไปยังระดับชั้นเรียนจะช่วยให้ SetFlagsRule.ClassRule
ตรวจสอบได้ว่ามีการตั้งค่าแฟล็กอย่างถูกต้องในระหว่างเครื่องมือสร้างของคลาสการทดสอบ หรือระหว่างเมธอด @BeforeClass
หรือ @AfterClass
ที่มีคำอธิบายประกอบ
ทำการทดสอบในการกำหนดค่า Flag หลายรายการ
เนื่องจากคุณกำหนดค่าแฟล็กได้ตามการทดสอบแต่ละครั้ง คุณใช้พารามิเตอร์เพื่อทำการทดสอบในการกำหนดค่า Flag หลายรายการได้ด้วย ดังนี้
...
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
คือtrue
FLAG_FOO
true
และFLAG_BAR
false
FLAG_FOO
คือfalse
และFLAG_BAR
คือtrue
FLAG_FOO
เป็นเท็จและFLAG_BAR
มีค่าเป็นfalse
คําอธิบายประกอบ @DisableFlags
และ @EnableFlags
จะแก้ไขค่า Flag ตามเงื่อนไขพารามิเตอร์แทนที่จะเปลี่ยนค่า Flag โดยตรง ตัวอย่างเช่น legacyBarLogic
จะทํางานเฉพาะเมื่อปิดใช้ FLAG_BAR
ซึ่งเกิดขึ้นในชุดค่าผสมของ Flag 2 ใน 4 ชุด ระบบจะข้าม legacyBarLogic
สำหรับ
อีก 2 ชุดค่าผสม
การสร้างการพารามิเตอร์สำหรับ Flag มี 2 วิธีดังนี้
FlagsParameterization.allCombinationsOf(String...)
เรียกใช้การทดสอบแต่ละรายการ 2^n ครั้ง เช่น แฟล็ก 1 รายการจะทำการทดสอบ 2 เท่า หรือ 4 รายการจะทำการทดสอบ 16 เท่าFlagsParameterization.progressionOf(String...)
เรียกใช้การทดสอบแต่ละรายการ n+1 ครั้ง เช่น มี 1 Flag ทำการทดสอบ 2 ครั้งและ 4 ครั้งทำการทดสอบ 5 ครั้ง
สร้างการทดสอบหน่วย (C และ C++)
AOSP มีมาโครค่า Flag สําหรับการทดสอบ 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
กำหนดชุด Flag ของรุ่นฟีเจอร์ที่ต้องเป็นไปตามเงื่อนไขที่เปิดใช้ ซึ่งคุณเขียนแฟล็กเหล่านี้ได้ในมาโครACONFIG_FLAG
หรือLEGACY_FLAG
REQUIRES_FLAGS_DISABLED
กำหนดชุด Flag ฟีเจอร์ที่ต้องเป็นไปตามเงื่อนไข "ปิดใช้" ซึ่งคุณเขียนแฟล็กเหล่านี้ได้ในมาโครACONFIG_FLAG
หรือLEGACY_FLAG
ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag)
เป็นมาโครที่ใช้สำหรับแฟล็กที่ระบุไว้ในไฟล์ aconfig มาโครนี้ยอมรับเนมสเปซ (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
หากปิดใช้ Flag
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)
สร้างการทดสอบแบบจุดต่อจุดหรือแบบหน่วยที่ค่าแฟล็กไม่มีการเปลี่ยนแปลง
สำหรับกรอบการทดสอบที่คุณลบล้างแฟล็กไม่ได้และกรองการทดสอบได้ก็ต่อเมื่อการทดสอบอิงตามสถานะ Flag ปัจจุบันเท่านั้น ให้ใช้กฎ CheckFlagsRule
กับคำอธิบายประกอบ RequiresFlagsEnabled
และ RequiresFlagsDisabled
ขั้นตอนต่อไปนี้แสดงวิธีสร้างและเรียกใช้การทดสอบจากต้นทางถึงปลายทางหรือการทดสอบหน่วยซึ่งไม่สามารถลบล้างค่า Flag ได้
ในโค้ดทดสอบ ให้ใช้
CheckFlagsRule
เพื่อใช้การกรองทดสอบ นอกจากนี้ ให้ใช้คำอธิบายประกอบของ JavaRequiresFlagsEnabled
และRequiredFlagsDisabled
เพื่อระบุข้อกำหนด Flag สำหรับการทดสอบของคุณการทดสอบฝั่งอุปกรณ์จะใช้คลาส
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
เริ่มต้นจะใช้ค่าแฟล็กจากอุปกรณ์ หากไม่ได้ลบล้างค่า Flag ในอุปกรณ์ เช่น adb ค่าเริ่มต้นจะเหมือนกับการกำหนดค่าการเผยแพร่ของบิลด์ หากมีการลบล้างค่าในอุปกรณ์ SetFlagsRule
จะใช้ค่าการลบล้างเป็นค่าเริ่มต้น
หากทำการทดสอบเดียวกันภายใต้การกำหนดค่ารุ่นที่แตกต่างกัน ค่าของ Flag ที่ไม่ได้ตั้งค่าอย่างชัดเจนด้วย SetFlagsRule
อาจแตกต่างกันไป
หลังจากการทดสอบแต่ละครั้ง SetFlagsRule
จะกู้คืนอินสแตนซ์ FeatureFlags
ใน Flags
กลับเป็น FeatureFlagsImpl
เดิม เพื่อไม่ให้ส่งผลเสียต่อเมธอดและคลาสทดสอบอื่นๆ