Özellik lansmanı bayrakları içindeki kodu test etme

Özellik lansmanı işaretlerinin kullanıma sunulmasıyla birlikte uymanız gereken yeni test politikaları ortaya çıktı:

  • Testleriniz, işaretin hem etkin hem de devre dışı bırakılmış davranışlarını kapsamalıdır.
  • Test sırasında işaret değerlerini ayarlamak için resmi mekanizmaları kullanmanız gerekir.
  • xTS testleri, testlerdeki işaret değerlerini geçersiz kılmamalıdır.

Sonraki bölümde, bu politikalara uymak için kullanmanız gereken resmi mekanizmalar açıklanmaktadır.

İşaretlenen kodunuzu test etme

Test senaryosu Kullanılan mekanizma
İşaret değerleri sık sık değiştiğinde yerel test Çalışma zamanında bir işaretin değerini değiştirme bölümünde ele alınan Android hata ayıklama köprüsü
İşaret değerleri sık sık değişmediğinde yerel test Özellik lansmanı işaret değerlerini ayarlama bölümünde açıklanan işaret değerleri dosyası
İşaret değerlerinin değiştiği uçtan uca test FeatureFlagTargetPreparer Uçtan uca testler oluşturma başlıklı makalede açıklandığı gibi
İşaret değerlerinin değiştiği birim testi Birim testleri oluşturma (Java ve Kotlin) veya Birim testleri oluşturma (C ve C++) bölümünde açıklandığı gibi SetFlagsRule ile @EnableFlags ve @DisableFlags
İşaret değerlerinin değişemediği uçtan uca veya birim testleri CheckFlagsRule İşaret değerlerinin değişmediği uçtan uca veya birim testleri oluşturma başlıklı makalede açıklandığı gibi

Uçtan uca testler oluşturma

AOSP, bir cihazda uçtan uca test yapmayı sağlayan FeatureFlagTargetPreparer adlı bir sınıf sunar. Bu sınıf, giriş olarak işaret değeri geçersiz kılmalarını kabul eder, test yürütülmeden önce cihaz yapılandırmasında bu işaretleri ayarlar ve yürütme işleminden sonra işaretleri geri yükler.

FeatureFlagTargetPreparer sınıfının işlevselliğini test modülü ve test yapılandırma düzeylerinde uygulayabilirsiniz.

FeatureFlagTargetPreparer'ı bir test modülü yapılandırmasında uygulama

Bir test modülü yapılandırmasında FeatureFlagTargetPreparer uygulamak için AndroidTest.xml test modülü yapılandırma dosyasına FeatureFlagTargetPreparer ve işaret değeri geçersiz kılmalarını ekleyin:

  <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>

Nerede:

  • target.preparer class her zaman com.android.tradefed.targetprep.FeatureFlagTargetPreparer olarak ayarlanır.
  • option, name her zaman flag-value ve value namespace/aconfigPackage.flagName=true|false olarak ayarlanmış işaret geçersiz kılma işlemidir.

İşaret durumlarına göre parametrelendirilmiş test modülleri oluşturma

İşaret durumlarına göre parametrelendirilmiş test modülleri oluşturmak için:

  1. AndroidTest.xml test modülü yapılandırma dosyasına FeatureFlagTargetPreparer öğesini ekleyin:

    <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >
    
  2. Android.bp derleme dosyasının test_module_config bölümünde işaret değeri seçeneklerini belirtin:

    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 alanı, name her zaman flag-value olarak ve value namespace/aconfigPackage.flagName=true|false olarak ayarlanmış işaret geçersiz kılmalarını içerir.

Birim testleri oluşturma (Java ve Kotlin)

Bu bölümde, Java ve Kotlin testlerinde sınıf ve yöntem düzeyinde (test başına) aconfig işareti değerlerini geçersiz kılma yaklaşımı açıklanmaktadır.

Çok sayıda işaret içeren büyük bir kod tabanında otomatik birim testleri yazmak için aşağıdaki adımları uygulayın:

  1. Tüm kod dallarını test etmek için SetFlagsRule sınıfını @EnableFlags ve @DisableFlags ek açıklamalarıyla birlikte kullanın.
  2. Sık karşılaşılan test hatalarından kaçınmak için SetFlagsRule.ClassRule yöntemini kullanın.
  3. Sınıflarınızı çeşitli işaret yapılandırmalarında test etmek için FlagsParameterization kullanın.

Tüm kod dallarını test etme

Statik sınıfı kullanarak işaretlere erişen projelerde, işaret değerlerini geçersiz kılmak için SetFlagsRule yardımcı sınıfı sağlanır. Aşağıdaki kod snippet'inde SetFlagsRule öğesinin nasıl ekleneceği ve birkaç işaretin aynı anda nasıl etkinleştirileceği gösterilmektedir:

  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() {
    ...
    }

Nerede:

  • @Rule, SetFlagsRule sınıfının flag-JUnit bağımlılığını eklemek için kullanılan bir ek açıklamadır.
  • SetFlagsRule, işaret değerlerini geçersiz kılmak için sağlanan yardımcı sınıftır. SetFlagsRule'nın varsayılan değerleri nasıl belirlediği hakkında bilgi için Cihaz varsayılan değerleri başlıklı makaleyi inceleyin.
  • @EnableFlags, rastgele sayıda işaret adı kabul eden bir ek açıklamadır. İşaretleri devre dışı bırakırken @DisableFlags kullanın. Bu ek açıklamaları bir yönteme veya sınıfa uygulayabilirsiniz.

Testteki @Before ile açıklama eklenmiş kurulum yöntemlerinden önce gelen SetFlagsRule ile başlayarak tüm test süreci için işaret değerlerini ayarlayın. SetFlagsRule tamamlandığında işaret değerleri önceki durumlarına döner. SetFlagsRule, @After ile açıklama eklenmiş tüm kurulum yöntemlerinden sonra tamamlanır.

İşaretlerin doğru şekilde ayarlandığından emin olun

Daha önce belirtildiği gibi SetFlagsRule, JUnit @Rule ek açıklamasıyla birlikte kullanılır. Bu nedenle SetFlagsRule, test sınıfının oluşturucusu veya @BeforeClass ya da @AfterClass ek açıklamalı yöntemler sırasında işaretlerinizin doğru şekilde ayarlandığından emin olamaz.

Test fikstürlerinin doğru sınıf değeriyle oluşturulduğundan emin olmak için SetFlagsRule.ClassRule yöntemini kullanın. Böylece fikstürleriniz, @Before ile açıklama eklenmiş bir kurulum yöntemi uygulanana kadar oluşturulmaz:

  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 sınıf kuralı eklendiğinde, FLAG_FLAG_FOO, DemoClass oluşturucusu tarafından okunurken test_flag_foo_turned_on çalışmadan önce başarısız olur.

Sınıfınızın tamamında bir işaretin etkinleştirilmesi gerekiyorsa @EnableFlags ek açıklamasını sınıf düzeyine (sınıf bildiriminden önce) taşıyın. Açıklamayı sınıf düzeyine taşıyarak SetFlagsRule.ClassRule, işaretin test sınıfının oluşturucusu sırasında veya @BeforeClass ya da @AfterClass açıklamalı yöntemler sırasında doğru şekilde ayarlandığından emin olabilir.

Birden çok işaret yapılandırmasında test çalıştırma

İşaret değerlerini test bazında ayarlayabildiğiniz için, parametrelendirmeyi kullanarak birden fazla işaret yapılandırmasında testler de çalıştırabilirsiniz:

...
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 ile ancak parametrelendirme olmadan bu sınıfın üç test (fooLogic, legacyBarLogic ve newBarLogic) çalıştırdığını unutmayın. fooLogic yöntemi, cihazda FLAG_FOO ve FLAG_BAR değerleri neye ayarlanmışsa onunla çalışır.

Parametreleştirme eklendiğinde FlagsParameterization.allCombinationsOf yöntemi, FLAG_FOO ve FLAG_BAR işaretlerinin tüm olası kombinasyonlarını oluşturur:

  • FLAG_FOO, true ve FLAG_BAR, true
  • FLAG_FOO, true ve FLAG_BAR, false
  • FLAG_FOO, false ve FLAG_BAR, true
  • FLAG_FOO yanlış ve FLAG_BAR, false

@DisableFlags ve @EnableFlags ek açıklamaları, işaret değerlerini doğrudan değiştirmek yerine parametre koşullarına göre değiştirir. Örneğin, legacyBarLogic yalnızca FLAG_BAR devre dışı bırakıldığında çalışır. Bu durum, dört işaret kombinasyonundan ikisinde görülür. Diğer iki kombinasyon için legacyBarLogic atlanır.

İşaretleriniz için parametreler oluşturmanın iki yöntemi vardır:

  • FlagsParameterization.allCombinationsOf(String...) her testin 2^n kez çalıştırılmasını sağlar. Örneğin, bir işaret 2x testleri veya dört işaret 16x testleri çalıştırır.

  • FlagsParameterization.progressionOf(String...), her testin n+1 çalışmasını yürütür. Örneğin, bir işaret 2x test çalıştırır ve dört işaret 5x işaret çalıştırır.

Birim testleri oluşturma (C ve C++)

AOSP, GoogleTest çerçevesinde yazılmış C ve C++ testleri için işaret değeri makroları içerir.

içinde bulabilirsiniz.
  1. Test kaynağınıza makro tanımlarını ve aconfig tarafından oluşturulan kitaplıkları ekleyin:

    #include <flag_macros.h>
    #include "android_cts_flags.h"
    
  2. Test kaynağınızda, test senaryolarınız için TEST ve TESTF makrolarını kullanmak yerine TEST_WITH_FLAGS ve TEST_F_WITH_FLAGS makrolarını kullanın:

    #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");
    }
    

    Nerede:

    • TEST ve TEST_F makroları yerine TEST_WITH_FLAGS ve TEST_F_WITH_FLAGS makroları kullanılır.
    • REQUIRES_FLAGS_ENABLED, etkin koşulunu karşılaması gereken bir dizi özellik yayınlama işareti tanımlar. Bu işaretleri ACONFIG_FLAG veya LEGACY_FLAG makrolarına yazabilirsiniz.
    • REQUIRES_FLAGS_DISABLED, devre dışı koşulunu karşılaması gereken bir dizi özellik işaretini tanımlar. Bu işaretleri ACONFIG_FLAG veya LEGACY_FLAG makrolarına yazabilirsiniz.
    • ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag), yapılandırma dosyalarında tanımlanan işaretler için kullanılan bir makrodur. Bu makro, bir ad alanı (TEST_NS) ve bir işaret adı (readwrite_enabled_flag) kabul eder.
    • LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag), cihaz yapılandırmasında varsayılan olarak ayarlanan işaretler için kullanılan bir makrodur.
  3. Android.bp derleme dosyanıza aconfig ile oluşturulan kitaplıkları ve ilgili makro kitaplıkları test bağımlılığı olarak ekleyin:

    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. Testleri yerel olarak çalıştırmak için şu komutu kullanın:

    atest FlagMacrosTests
    

    my_namespace.android.myflag.tests.my_flag işareti devre dışıysa test sonucu:

    [1/2] MyTest#test1: IGNORED (0ms)
    [2/2] MyTestF#test2: PASSED (0ms)
    

    my_namespace.android.myflag.tests.my_flag işareti etkinse test sonucu:

    [1/2] MyTest#test1: PASSED (0ms)
    [2/2] MyTestF#test2: IGNORED (0ms)
    

İşaret değerlerinin değişmediği uçtan uca veya birim testleri oluşturun.

İşaretlerin geçersiz kılınamadığı ve testlerin yalnızca mevcut işaret durumuna göre filtrelenebildiği test senaryolarında, CheckFlagsRule kuralını RequiresFlagsEnabled ve RequiresFlagsDisabled ek açıklamalarıyla birlikte kullanın.

Aşağıdaki adımlarda, işaret değerlerinin geçersiz kılınamayacağı uçtan uca veya birim testi oluşturma ve çalıştırma işlemleri gösterilmektedir:

  1. Test kodunuzda test filtreleme uygulamak için CheckFlagsRule simgesini kullanın. Ayrıca, testiniz için işaret gereksinimlerini belirtmek üzere RequiresFlagsEnabled ve RequiredFlagsDisabled Java ek açıklamalarını kullanın.

    Cihaz tarafı testi için DeviceFlagsValueProvider sınıfı kullanılır:

    @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() {}
    }
    

    Ana makine tarafındaki testte HostFlagsValueProvider sınıfı kullanılır:

    @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 ve aconfig tarafından oluşturulan kitaplıkları, testinizin derleme dosyasının static_libs bölümüne ekleyin:

    android_test {
        name: "FlagAnnotationTests",
        srcs: ["*.java"],
        static_libs: [
            "androidx.test.rules",
            "my_aconfig_lib",
            "flag-junit",
            "platform-test-annotations",
        ],
        test_suites: ["general-tests"],
    }
    
  3. Testi yerel olarak çalıştırmak için aşağıdaki komutu kullanın:

    atest FlagAnnotationTests
    

    Flags.FLAG_FLAG_NAME_1 işareti devre dışıysa test sonucu:

    [1/2] com.cts.flags.FlagAnnotationTest#test1: ASSUMPTION_FAILED (10ms)
    [2/2] com.cts.flags.FlagAnnotationTest#test2: PASSED (2ms)
    

    Aksi takdirde test sonucu şöyledir:

    [1/2] com.cts.flags.FlagAnnotationTest#test1: PASSED (2ms)
    [2/2] com.cts.flags.FlagAnnotationTest#test2: ASSUMPTION_FAILED (10ms)
    

Cihaz varsayılan değerleri

Başlatılan SetFlagsRule, cihazdaki işaret değerlerini kullanır. Cihazdaki işaret değeri, adb gibi bir yöntemle geçersiz kılınmazsa varsayılan değer, derlemenin yayın yapılandırmasıyla aynı olur. Cihazdaki değer geçersiz kılınmışsa SetFlagsRule, geçersiz kılma değerini varsayılan olarak kullanır.

Aynı test farklı yayın yapılandırmaları altında yürütülürse SetFlagsRule ile açıkça ayarlanmamış işaretlerin değeri değişebilir.

Her testten sonra SetFlagsRule, Flags içindeki FeatureFlags örneğini orijinal FeatureFlagsImpl durumuna geri yükler. Böylece, diğer test yöntemleri ve sınıfları üzerinde yan etkileri olmaz.