Özellik lansman bayraklarında kodu test edin

Özellik lansman flag'lerinin kullanıma sunulmasıyla birlikte uymanız gereken yeni test politikaları var:

  • Testleriniz, işaretin hem etkin hem de devre dışı 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 değiştiğinde yerel test Çalışma zamanında bir işaretin değerini değiştirme konusunda açıklandığı gibi Android hata ayıklama köprüsü
İşaret değerleri sık sık değişmediğinde yerel test Değerleri, Özellik kullanıma sunma işareti değerlerini belirleme bölümünde açıklandığı gibi işaretleme
İşaret değerlerinin değiştiği uçtan uca test FeatureFlagTargetPreparer Uçtan uca test oluşturma bölümünde açıklandığı gibi
İşaret değerlerinin değiştiği birim testi Birim testi oluşturma (Java ve Kotlin) veya Birim testi oluşturma (C ve C++) bölümünde açıklandığı gibi @EnableFlags ve @DisableFlags ile SetFlagsRule
İşaret değerlerinin değişmediği uçtan uca veya birim testi İşaret değerlerinin değişmediği uçtan uca veya birim testler oluşturma konusunda açıklandığı gibi CheckFlagsRule

Uçtan uca testler oluşturma

AOSP, cihazda uçtan uca test yapılmasına olanak tanıyan FeatureFlagTargetPreparer adında bir sınıf sağlar. Bu sınıf, giriş olarak işaret değeri geçersiz kılma işlemlerini kabul eder, test çalıştırmadan önce bu işaretleri cihaz yapılandırmasında ayarlar ve çalıştırma işleminden sonra işaretleri geri yükler.

FeatureFlagTargetPreparer sınıfının işlevlerini test modülünde uygulayabilir ve test yapılandırması düzeylerinde yapabilirsiniz.

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

FeatureFlagTargetPreparer'ü bir test modülü yapılandırmasına uygulamak için FeatureFlagTargetPreparer ve işaret değeri geçersiz kılma işlemlerini AndroidTest.xml test modülü yapılandırma dosyasına 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, işaret geçersiz kılma işlemidir. name her zaman flag-value olarak, value ise namespace/aconfigPackage.flagName=true|false olarak ayarlanır.

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

İşaret durumlarına dayalı parametre haline getirilmiş 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 değerinin her zaman flag-value ve value değerinin namespace/aconfigPackage.flagName=true|false olarak ayarlandığı 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) yapılandırma işareti değerlerini geçersiz kılma yaklaşımı açıklanmaktadır.

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

  1. Tüm kod dallarını test etmek için @EnableFlags ve @DisableFlags ek açıklamalarıyla SetFlagsRule sınıfını 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 seçeneğini kullanın.

Tüm kod dallarını test etme

İşaretlere erişmek için statik sınıfı kullanan 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'i, SetFlagsRule öğesinin nasıl dahil edileceğini ve birkaç işaretin aynı anda nasıl etkinleştirileceğini gösterir:

  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 hizmetinin varsayılan değerleri nasıl belirlediği hakkında bilgi edinmek için Cihaz varsayılan değerleri bölümüne bakın.
  • @EnableFlags, isteğe bağlı sayıda işaret adını 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 ek açıklamalı kurulum yöntemlerinden önce gelen SetFlagsRule ile başlayarak test sürecinin tamamı için işaret değerleri belirleyin. İşaretleme değerleri, SetFlagsRule tamamlandığında (@After ek açıklamalı tüm kurulum yöntemlerinden sonra) önceki durumlarına döner.

İşaretçilerin doğru şekilde ayarlandığından emin olun

Daha önce de belirtildiği gibi SetFlagsRule, JUnit @Rule ek açıklamasıyla birlikte kullanılır. Bu, SetFlagsRule ürününün, test sınıfının oluşturucusu veya @BeforeClass ya da @AfterClass ek açıklamalı herhangi bir yöntem sırasında işaretlerinizin doğru bir şekilde ayarlandığından emin olamayacağı anlamına gelir.

Test armatürlerinin doğru sınıf değeriyle oluşturulduğundan emin olmak için SetFlagsRule.ClassRule yöntemini kullanın. Böylece, @Before ek açıklamalı bir kurulum yöntemine kadar armatürlerinizin oluşturulmaması sağlanır:

  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 sınıfının kurucusu tarafından okunduğunda test_flag_foo_turned_on çalıştırılmadan önce başarısız olur.

Sınıfınızın tamamı için bir işaretin etkinleştirilmesi gerekiyorsa @EnableFlags ek açıklamasını sınıf düzeyine (sınıf beyanı öncesine) taşıyın. Ek açıklamanın sınıf düzeyine taşınması, SetFlagsRule.ClassRule ürününün, test sınıfının oluşturucusu sırasında veya @BeforeClass ya da @AfterClass ek açıklamalı herhangi bir yöntem sırasında işaretin doğru bir şekilde ayarlandığından emin olmasını sağlar.

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

İşaret değerlerini test başına ayarlayabileceğiniz için birden fazla işaret yapılandırmasında test çalıştırmak için parametrelendirmeyi de kullanabilirsiniz:

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

Bu sınıfın, SetFlagsRule ile ancak parametre olmadan üç test (fooLogic, legacyBarLogic ve newBarLogic) çalıştırdığını unutmayın. fooLogic yöntemi, cihazda FLAG_FOO ve FLAG_BAR değerlerinin ayarlandığı şekilde çalışır.

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

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

@DisableFlags ve @EnableFlags ek açıklamaları, işaret değerlerini doğrudan değiştirmek yerine parametre koşullarına göre işaret değerlerini 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 gerçekleşir. Diğer iki kombinasyon için legacyBarLogic atlanır.

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

  • FlagsParameterization.allCombinationsOf(String...), her testi 2^n kez çalıştırır. Örneğin, bir işaret 2 kat daha fazla test, dört işaret ise 16 kat daha fazla test çalıştırır.

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

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

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

  1. Test kaynağınıza makro tanımlarını ve yapılandırma tarafından oluşturulan kitaplıkları ekleyin:

    #include <flag_macros.h>
    #include "android_cts_flags.h"
    
  2. Test kaynağınızda, test durumlarınız için TEST ve TESTF makroları yerine TEST_WITH_FLAGS ve TEST_F_WITH_FLAGS değerlerini 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ıyor.
    • REQUIRES_FLAGS_ENABLED, etkin koşulunu karşılaması gereken bir dizi özellik yayınlama işaretini tanımlar. Bu işaretleri ACONFIG_FLAG veya LEGACY_FLAG makrolarına yazabilirsiniz.
    • REQUIRES_FLAGS_DISABLED, devre dışı bırakılmış koşulu 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, ad alanını (TEST_NS) ve işaret adını (readwrite_enabled_flag) kabul eder.
    • LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag), varsayılan olarak cihaz yapılandırmasında ayarlanan işaretler için kullanılan bir makrodur.
  3. Android.bp derleme dosyanıza, aconfig tarafından oluşturulan kitaplıkları ve ilgili makro kitaplıklarını 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 şu komutla yerel olarak çalıştırın:

    atest FlagMacrosTests
    

    my_namespace.android.myflag.tests.my_flag işareti devre dışı bırakılırsa test sonucu şu şekilde olur:

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

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

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

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

İşaretleri geçersiz kılamayacağınız ve testleri yalnızca geçerli işaretleme durumuna dayalı olmaları koşuluyla filtreleyebileceğiniz test durumları için RequiresFlagsEnabled ve RequiresFlagsDisabled ek açıklamalarıyla CheckFlagsRule kuralını kullanın.

Aşağıdaki adımlarda, işaret değerlerinin geçersiz kılınamayacağı uçtan uca veya birim testinin nasıl oluşturulacağı ve çalıştırılacağı gösterilmektedir:

  1. Test filtrelemesi uygulamak için test kodunuzda CheckFlagsRule kullanın. Ayrıca, testinizin işaret gereksinimlerini belirtmek için RequiresFlagsEnabled ve RequiredFlagsDisabled Java ek açıklamalarını kullanın.

    Cihaz tarafı testinde 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ı testi HostFlagsValueProvider sınıfını kullanı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. Testiniz için derleme dosyasının static_libs bölümüne jflag-unit ve aconfig tarafından oluşturulan kitaplıkları 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ışı bırakılırsa test sonucu şu şekilde olur:

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

    Aksi takdirde test sonucu şöyle olur:

    [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 geçersiz kılınmamışsa (ör. adb ile) varsayılan değer, derlemenin sürüm yapılandırmasıyla aynıdır. Cihazdaki değer geçersiz kılınmışsa SetFlagsRule, varsayılan olarak geçersiz kılma değerini kullanır.

Aynı test farklı sürüm yapılandırmaları altında yürütülürse SetFlagsRule ile açıkça ayarlanmayan işaretlerin değeri değişiklik gösterebilir.

SetFlagsRule, her testten sonra 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 etki oluşmaz.