کد را در پرچم های راه اندازی ویژگی تست کنید

با معرفی پرچم‌های راه‌اندازی ویژگی، خط‌مشی‌های آزمایشی جدیدی وجود دارد که باید از آنها پیروی کنید:

  • آزمایشات شما باید هم رفتارهای فعال و هم غیرفعال شده پرچم را پوشش دهد.
  • شما باید از مکانیسم های رسمی برای تنظیم مقادیر پرچم در طول آزمایش استفاده کنید.
  • تست‌های xTS نباید مقادیر پرچم را در تست‌ها نادیده بگیرند.

بخش بعدی مکانیسم‌های رسمی را که باید برای پایبندی به این سیاست‌ها استفاده کنید، ارائه می‌کند.

کد پرچم گذاری شده خود را تست کنید

سناریوی تست مکانیزم استفاده شده
آزمایش محلی هنگامی که مقادیر پرچم اغلب تغییر می کند پل اشکال زدایی اندروید همانطور که در Change a flag's value در زمان اجرا توضیح داده شد
آزمایش محلی زمانی که مقادیر پرچم اغلب تغییر نمی کند فایل مقادیر پرچم را همانطور که در مقادیر پرچم راه اندازی ویژگی Set بحث شده است
آزمایش سرتاسر که در آن مقادیر پرچم تغییر می کند FeatureFlagTargetPreparer همانطور که در Create end-to-end tests بحث شد
تست واحد که در آن مقادیر پرچم تغییر می کند SetFlagsRule با @EnableFlags و @DisableFlags همانطور که در تست های Create unit (جاوا و کاتلین) یا Create unit tests (C و C++) بحث شده است.
آزمایش سرتاسر یا واحد که در آن مقادیر پرچم نمی‌توانند تغییر کنند 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 است.

ماژول های آزمایشی پارامتری را بر اساس وضعیت های پرچم ایجاد کنید

برای ایجاد ماژول های تست پارامتری بر اساس وضعیت های پرچم:

  1. FeatureFlagTargetPreparer در فایل پیکربندی ماژول تست AndroidTest.xml قرار دهید:

    <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >
    
  2. گزینه های مقدار پرچم را در بخش 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 تنظیم شده است.

ایجاد تست واحد (جاوا و کاتلین)

این بخش روشی را برای نادیده گرفتن مقادیر پرچم aconfig در سطح کلاس و روش (در هر آزمون) در تست‌های جاوا و کاتلین توضیح می‌دهد.

برای نوشتن تست های واحد خودکار در یک پایگاه کد بزرگ با تعداد زیادی پرچم، این مراحل را دنبال کنید:

  1. از کلاس SetFlagsRule با حاشیه نویسی @EnableFlags و @DisableFlags برای آزمایش همه شاخه های کد استفاده کنید.
  2. از روش SetFlagsRule.ClassRule برای جلوگیری از باگ های رایج تست استفاده کنید.
  3. از 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 یک کلاس کمکی است که برای نادیده گرفتن مقادیر پرچم ارائه شده است. برای اطلاعات در مورد نحوه تعیین مقادیر پیش فرض SetFlagsRule ، به مقادیر پیش فرض دستگاه مراجعه کنید.
  • @EnableFlags یک حاشیه نویسی است که تعداد دلخواه نام پرچم را می پذیرد. هنگام غیرفعال کردن پرچم‌ها، از @DisableFlags استفاده کنید. شما می توانید این حاشیه نویسی را برای یک متد یا یک کلاس اعمال کنید.

مقادیر پرچم را برای کل فرآیند تست تنظیم کنید، از SetFlagsRule شروع کنید، که قبل از هر روش تنظیم @Before -annotated در تست است. زمانی که SetFlagsRule تمام می شود، مقادیر پرچم به حالت قبلی خود باز می گردند، که پس از هر روش تنظیم @After -annotated است.

مطمئن شوید که پرچم ها به درستی تنظیم شده اند

همانطور که قبلا ذکر شد، SetFlagsRule با حاشیه نویسی JUnit @Rule استفاده می شود، به این معنی که SetFlagsRule نمی تواند اطمینان حاصل کند که پرچم های شما به درستی در طول سازنده کلاس تست، یا هر روش @BeforeClass یا @AfterClass -annotated تنظیم شده است.

برای اطمینان از اینکه فیکسچرهای آزمایشی با مقدار کلاس درست ساخته شده اند، از روش SetFlagsRule.ClassRule استفاده کنید تا وسایل شما تا زمانی که یک روش تنظیم @Before -annotated ایجاد نشود:

  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_FOO true است و FLAG_BAR true است
  • FLAG_FOO true است و FLAG_BAR false است
  • FLAG_FOO false است و FLAG_BAR true است
  • FLAG_FOO نادرست و FLAG_BAR false است

به جای تغییر مستقیم مقادیر پرچم، حاشیه نویسی @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 نوشته شده‌اند.

  1. در منبع آزمایشی خود، تعاریف ماکرو و کتابخانه های ایجاد شده توسط aconfig را وارد کنید:

    #include <flag_macros.h>
    #include "android_cts_flags.h"
    
  2. در منبع آزمایشی خود، به جای استفاده از ماکروهای 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) یک ماکرو است که برای پرچم‌هایی که به طور پیش‌فرض در پیکربندی دستگاه تنظیم شده‌اند استفاده می‌شود.
  3. در فایل ساخت 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"],
      ...
    }
    
  4. با این دستور تست ها را به صورت محلی اجرا کنید:

    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 استفاده کنید.

مراحل زیر به شما نشان می‌دهد که چگونه می‌توانید یک تست سرتاسر یا واحد را ایجاد و اجرا کنید که در آن مقادیر پرچم قابل لغو نیستند:

  1. در کد تست خود، از 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() {}
    }
    
  2. کتابخانه های jflag-unit و aconfig-generated را برای آزمایش خود به بخش 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"],
    }
    
  3. برای اجرای تست به صورت محلی از دستور زیر استفاده کنید:

    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 از مقدار override به عنوان پیش فرض استفاده می کند.

اگر همان آزمایش تحت پیکربندی های مختلف انتشار اجرا شود، مقدار پرچم هایی که به طور صریح با SetFlagsRule تنظیم نشده اند، می تواند متفاوت باشد.

پس از هر آزمایش، SetFlagsRule نمونه FeatureFlags در Flags را به FeatureFlagsImpl اصلی خود بازیابی می کند، به طوری که عوارض جانبی روی روش ها و کلاس های تست دیگر نداشته باشد.