בעקבות ההשקה של דגלים להשקת תכונות, יש כללי מדיניות חדשים לבדיקות שאתם צריכים לפעול לפיהם:
- הבדיקות צריכות לכלול את ההתנהגויות של הדגל גם כשהוא מופעל וגם כשהוא מושבת.
- צריך להשתמש במנגנונים הרשמיים כדי להגדיר ערכי דגלים במהלך הבדיקה.
- בדיקות xTS לא אמורות לשנות את ערכי הדגלים בבדיקות.
בקטע הבא מפורטים המנגנונים הרשמיים שבהם עליכם להשתמש כדי לעמוד בדרישות המדיניות האלה.
בדיקת הקוד שסומן
תרחיש בדיקה | המנגנון שבו נעשה שימוש |
---|---|
בדיקה מקומית כשערכי הדגלים משתנים לעיתים קרובות | Android debug bridge כפי שמתואר בקטע שינוי הערך של דגל בזמן הריצה |
בדיקה מקומית כשערכי הדגלים לא משתנים לעיתים קרובות | קובץ ערכים של דגלים, כפי שמתואר בקטע הגדרת ערכים של דגלים להשקת תכונות |
בדיקה מקצה לקצה שבה ערכי הדגלים משתנים | FeatureFlagTargetPreparer כפי שמתואר במאמר יצירת בדיקות מקצה לקצה |
בדיקת יחידה שבה ערכי הדגלים משתנים | SetFlagsRule עם @EnableFlags ו-@DisableFlags כפי שמתואר במאמר יצירת בדיקות יחידה (Java ו-Kotlin) או במאמר יצירת בדיקות יחידה (C ו-C++) |
בדיקות מקצה לקצה או בדיקות יחידה (unit testing) שבהן ערכים של דגלים לא יכולים להשתנות | CheckFlagsRule כפי שמתואר במאמר יצירת בדיקות מקצה לקצה או בדיקות יחידה שבהן ערכי הדגלים לא משתנים |
יצירת בדיקות מקצה לקצה
ב-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
בקובץ ה-build 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.
כדי לכתוב בדיקות יחידה אוטומטיות בקוד בסיס גדול עם מספר גדול של דגלים, צריך לפעול לפי השלבים הבאים:
- כדי לבדוק את כל הענפים של הקוד, משתמשים בכיתה
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
היא הערה שמשמשת להוספת התלות של הדגל ב-JUnit לכיתהSetFlagsRule
.SetFlagsRule
היא כיתת עזר שמיועדת לשינוי ערכי הדגלים. במאמר ערכי ברירת מחדל של המכשיר מוסבר איךSetFlagsRule
קובע את ערכי ברירת המחדל.@EnableFlags
הוא הערה שמקבלת מספר שרירותי של שמות דגלים. כשמשביתים דגלים, משתמשים ב-@DisableFlags
. אפשר להחיל את ההערות האלה על שיטה או על כיתה.
מגדירים ערכי דגלים לכל תהליך הבדיקה, החל מ-SetFlagsRule
, לפני כל שיטות ההגדרה עם ההערה @Before
בבדיקה. ערכי הדגלים חוזרים למצב הקודם כשה-SetFlagsRule
מסתיים, כלומר אחרי כל שיטות ההגדרה עם ההערות של @After
.
מוודאים שהדגלים מוגדרים בצורה נכונה
כפי שצוין קודם, SetFlagsRule
משמש עם ההערה @Rule
של JUnit, כלומר SetFlagsRule
לא יכול להבטיח שהדגלים מוגדרים בצורה נכונה במהלך ה-constructor של סוג הבדיקה, או בכל שיטות עם ההערה @BeforeClass
או @AfterClass
.
כדי לוודא שהאביזר לבדיקה נוצר עם ערך הכיתה הנכון, צריך להשתמש ב-method SetFlagsRule.ClassRule
כדי שהאביזר לא נוצר עד ש-method ההגדרה מתויג ב-@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
להיכשל לפני הריצה, כש-FLAG_FLAG_FOO
נקרא על ידי ה-constructor של DemoClass
.
אם צריך להפעיל את הדגל בכיתה כולה, מעבירים את ההערה @EnableFlags
לרמת הכיתה (לפני הצהרת הכיתה). העברת ההערה לרמת הכיתה מאפשרת ל-SetFlagsRule.ClassRule
לוודא שהדגל מוגדר בצורה נכונה במהלך ה-constructor של כיתה הבדיקה, או במהלך שיטות עם הערה של @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
, אבל בלי הגדרת פרמטרים, הכיתה הזו מפעילה שלושה בדיקות (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
הוא false והערך שלFLAG_BAR
הואfalse
במקום לשנות את ערכי הדגלים ישירות, הערות @DisableFlags
ו-@EnableFlags
משנות את ערכי הדגלים על סמך תנאי הפרמטרים. לדוגמה, הפקודה legacyBarLogic
פועלת רק כשהפקודה FLAG_BAR
מושבתת, וזה קורה בשתי מתוך ארבע שילובי הדגלים. ה-legacyBarLogic
מושמט בשני השילובים האחרים.
יש שתי שיטות ליצירת הפרמטרים של הדגלים:
FlagsParameterization.allCombinationsOf(String...)
מבצע 2^n הפעלות של כל בדיקה. לדוגמה, דגל אחד מפעיל 2x בדיקות או ש-4 דגלים מפעילים 16x בדיקות.FlagsParameterization.progressionOf(String...)
מפעיל n+1 פעולות של כל בדיקה. לדוגמה, דגל אחד מפעיל 2x בדיקות וארבעה דגלים מפעילים 5x דגלים.
יצירת בדיקות יחידה (C ו-C++)
AOSP כולל פקודות מאקרו של ערכי דגלים לבדיקות C ו-C++ שנכתבו במסגרת GoogleTest.
במקור הבדיקה, צריך לכלול את הגדרות המאקרו ואת הספריות שנוצרו על ידי aconfig:
#include <flag_macros.h> #include "android_cts_flags.h"
במקור הבדיקה, במקום להשתמש במאקרו
TEST
ובמאקרוTESTF
בתרחישי הבדיקה, משתמשים ב-TEST_WITH_FLAGS
וב-TEST_F_WITH_FLAGS
:#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)
הוא מאקרו שמשמש לדגלים שמוגדרים בקובצי aconfig. המאקרו הזה מקבל מרחב שמות (TEST_NS
) ושם של דגל (readwrite_enabled_flag
).LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag)
הוא מאקרו שמשתמש בדגלים שמוגדרים בהגדרות המכשיר כברירת מחדל.
- משתמשים במאקרו
בקובץ ה-build
Android.bp
, מוסיפים את הספריות שנוצרו על ידי aconfig ואת ספריות המאקרו הרלוונטיות כיחסי תלות לבדיקה: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
בקובץ ה-build של הבדיקה: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, ערך ברירת המחדל יהיה זהה להגדרת הגרסה של ה-build. אם הערך במכשיר השתנה, הערך החדש ישמש בתור ברירת המחדל ב-SetFlagsRule
.
אם מריצים את אותו הבדיקה בהגדרות שונות של גרסאות, הערך של הדגלים שלא מוגדרים באופן מפורש באמצעות SetFlagsRule
עשוי להשתנות.
אחרי כל בדיקה, SetFlagsRule
משחזר את מופע FeatureFlags
ב-Flags
ל-FeatureFlagsImpl
המקורי, כדי שלא יהיו לו השפעות לוואי על שיטות בדיקה וסוגים אחרים.