با معرفی پرچمهای راهاندازی ویژگی، سیاستهای تست جدیدی وجود دارد که باید به آنها پایبند باشید:
- آزمایشهای شما باید هر دو رفتار فعال و غیرفعال پرچم را پوشش دهند.
- شما باید از سازوکارهای رسمی برای تنظیم مقادیر پرچم در طول آزمایش استفاده کنید.
- تستهای xTS نباید مقادیر پرچم را در تستها لغو کنند.
بخش بعدی سازوکارهای رسمی مورد نیاز برای پایبندی به این سیاستها را ارائه میدهد.
کد علامتگذاری شده خود را آزمایش کنید
| سناریوی آزمایش | مکانیسم مورد استفاده |
|---|---|
| تست محلی زمانی که مقادیر پرچم اغلب تغییر میکنند | پل اشکالزدایی اندروید، همانطور که در تغییر مقدار یک پرچم در زمان اجرا بحث شد |
| تست محلی زمانی که مقادیر پرچم اغلب تغییر نمیکنند | فایل مقادیر پرچم همانطور که در بخش «تنظیم مقادیر پرچم راهاندازی ویژگی» بحث شد، ذخیره میشود. |
| تست سرتاسری که در آن مقادیر پرچم تغییر میکنند | FeatureFlagTargetPreparer همانطور که در بخش ایجاد تستهای سرتاسری بحث شد |
| تست واحد که در آن مقادیر پرچم تغییر میکنند | همانطور که در بخش ایجاد تستهای واحد (جاوا و کاتلین) یا ایجاد تستهای واحد (سی و سی پلاس پلاس) بحث شد، SetFlagsRule با @EnableFlags و @DisableFlags تنظیم کنید. |
| تست سرتاسری یا واحد که در آن مقادیر پرچم نمیتوانند تغییر کنند | CheckFlagsRule همانطور که در بخش ایجاد تستهای سرتاسری یا واحد که مقادیر پرچم تغییر نمیکنند، بحث شده است. |
ایجاد تستهای سرتاسری
AOSP کلاسی به نام FeatureFlagTargetPreparer ارائه میدهد که امکان تست سرتاسری (end-to-end testing) را روی یک دستگاه فراهم میکند. این کلاس مقادیر 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شامل لغو flag است کهnameهمیشه رویflag-valueوvalueرویnamespace/aconfigPackage.flagName=true|falseتنظیم شده است.
ایجاد تستهای واحد (جاوا و کاتلین)
این بخش رویکرد لغو مقادیر پرچم aconfig در سطح کلاس و متد (به ازای هر تست) در تستهای جاوا و کاتلین را شرح میدهد.
برای نوشتن تستهای واحد خودکار در یک پایگاه کد بزرگ با تعداد زیادی پرچم، این مراحل را دنبال کنید:
- از کلاس
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یک حاشیهنویسی است که برای اضافه کردن وابستگی flag-JUnit به کلاسSetFlagsRuleاستفاده میشود. -
SetFlagsRuleیک کلاس کمکی است که برای لغو مقادیر flag ارائه شده است. برای اطلاعات بیشتر در مورد نحوه تعیین مقادیر پیشفرضSetFlagsRule، به مقادیر پیشفرض دستگاه مراجعه کنید. -
@EnableFlagsیک حاشیهنویسی است که تعداد دلخواهی از نامهای پرچم را میپذیرد. هنگام غیرفعال کردن پرچمها، از@DisableFlagsاستفاده کنید. میتوانید این حاشیهنویسیها را روی یک متد یا یک کلاس اعمال کنید.
مقادیر پرچم را برای کل فرآیند تست تنظیم کنید، که با SetFlagsRule شروع میشود، که قبل از هر متد راهاندازی @Before -annotated در تست قرار دارد. مقادیر پرچم پس از اتمام SetFlagsRule به حالت قبلی خود برمیگردند، که بعد از هر متد راهاندازی @After -annotated است.
مطمئن شوید که پرچمها (flags) به درستی تنظیم شدهاند
همانطور که قبلاً ذکر شد، SetFlagsRule با حاشیهنویسی JUnit @Rule استفاده میشود، به این معنی که SetFlagsRule نمیتواند اطمینان حاصل کند که پرچمهای شما در طول سازنده کلاس تست یا هر متد حاشیهنویسی شده @BeforeClass یا @AfterClass به درستی تنظیم شدهاند.
برای اطمینان از اینکه fixture های آزمایشی با مقدار کلاس صحیح ساخته میشوند، از متد SetFlagsRule.ClassRule استفاده کنید تا fixture های شما تا زمانی که یک متد setup با حاشیهنویسی @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 توسط سازندهی DemoClass خوانده میشود، با شکست مواجه میشود.
اگر کل کلاس شما نیاز به فعال کردن یک پرچم دارد، حاشیهنویسی @EnableFlags را به سطح کلاس (قبل از تعریف کلاس) منتقل کنید. انتقال حاشیهنویسی به سطح کلاس به SetFlagsRule.ClassRule اجازه میدهد تا اطمینان حاصل کند که پرچم در طول سازنده کلاس آزمایشی یا در طول هر یک از متدهای @BeforeClass یا @AfterClass -annotated به درستی تنظیم شده است.
اجرای تستها در پیکربندیهای مختلف پرچم
از آنجا که میتوانید مقادیر پرچم را بر اساس هر آزمون تنظیم کنید، میتوانید از پارامتربندی برای اجرای آزمونها در چندین پیکربندی پرچم نیز استفاده کنید:
...
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_FOOtrueاست وFLAG_BARtrueاست -
FLAG_FOOtrueوFLAG_BARfalseاست. -
FLAG_FOOfalseوFLAG_BARtrueاست. -
FLAG_FOOنادرست وFLAG_BARfalseاست.
به جای تغییر مستقیم مقادیر پرچم، حاشیهنویسیهای @DisableFlags و @EnableFlags مقادیر پرچم را بر اساس شرایط پارامتر تغییر میدهند. برای مثال، legacyBarLogic فقط زمانی اجرا میشود که FLAG_BAR غیرفعال باشد، که در دو مورد از چهار ترکیب پرچم رخ میدهد. legacyBarLogic برای دو ترکیب دیگر نادیده گرفته میشود.
دو روش برای ایجاد پارامتربندی برای پرچمهای شما وجود دارد:
FlagsParameterization.allCombinationsOf(String...)2^n بار از هر تست را اجرا میکند. برای مثال، یک فلگ 2x تست یا چهار فلگ 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مجموعهای از feature flags را تعریف میکند که باید شرایط غیرفعال بودن را داشته باشند. میتوانید این flags را در ماکروهای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 و کتابخانههای ماکروی مربوطه را به عنوان یک وابستگی آزمایشی اضافه کنید: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برای اعمال فیلترینگ تست استفاده کنید. همچنین، از حاشیهنویسیهای جاواRequiresFlagsEnabledو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-generated را به بخش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، مقدار پیشفرض همان پیکربندی انتشار ساخت است. اگر مقدار روی دستگاه لغو شده باشد، SetFlagsRule از مقدار لغو شده به عنوان پیشفرض استفاده میکند.
اگر همان تست تحت پیکربندیهای انتشار مختلف اجرا شود، مقدار پرچمهایی که به صراحت با SetFlagsRule تنظیم نشدهاند، میتوانند متفاوت باشند.
پس از هر تست، SetFlagsRule نمونه FeatureFlags را در Flags به FeatureFlagsImpl اصلی آن بازیابی میکند، به طوری که روی سایر متدها و کلاسهای تست عوارض جانبی نداشته باشد.