Dengan diperkenalkannya tanda peluncuran fitur, ada kebijakan pengujian baru yang harus Anda patuhi:
- Pengujian Anda harus mencakup perilaku aktif dan nonaktif flag.
- Anda harus menggunakan mekanisme resmi untuk menetapkan nilai flag selama pengujian.
- Pengujian xTS tidak boleh menggantikan nilai flag dalam pengujian.
Bagian berikutnya memberikan mekanisme resmi yang harus Anda gunakan untuk mematuhi kebijakan ini.
Menguji kode yang ditandai
| Skenario pengujian | Mekanisme yang digunakan |
|---|---|
| Pengujian lokal saat nilai tanda sering berubah | Android Debug Bridge seperti yang dibahas dalam Mengubah nilai flag saat runtime |
| Pengujian lokal saat nilai flag tidak sering berubah | File nilai tanda seperti yang dibahas dalam Menetapkan nilai tanda peluncuran fitur |
| Pengujian menyeluruh saat nilai flag berubah | FeatureFlagTargetPreparer seperti yang dibahas dalam Membuat pengujian menyeluruh |
| Pengujian unit saat nilai flag berubah | SetFlagsRule dengan @EnableFlags dan @DisableFlags seperti yang dibahas dalam Membuat pengujian unit (Java dan Kotlin) atau
Membuat pengujian unit (C dan C++) |
| Pengujian unit atau end-to-end yang nilai tanda fiturnya tidak dapat berubah | CheckFlagsRule seperti yang dibahas dalam Membuat pengujian unit atau end-to-end saat nilai tanda tidak berubah |
Membuat pengujian menyeluruh
AOSP menyediakan class yang disebut FeatureFlagTargetPreparer, yang memungkinkan
pengujian end-to-end di perangkat. Class ini menerima penggantian nilai tanda sebagai
input, menetapkan tanda tersebut dalam konfigurasi perangkat sebelum eksekusi pengujian,
dan memulihkan tanda setelah eksekusi.
Anda dapat menerapkan fungsi class FeatureFlagTargetPreparer di tingkat modul pengujian dan konfigurasi pengujian.
Menerapkan FeatureFlagTargetPreparer dalam konfigurasi modul pengujian
Untuk menerapkan FeatureFlagTargetPreparer dalam konfigurasi modul pengujian, sertakan
penggantian nilai tanda dan FeatureFlagTargetPreparer dalam file konfigurasi
modul pengujian 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>
Dalam hal ini:
target.preparer classselalu disetel kecom.android.tradefed.targetprep.FeatureFlagTargetPreparer.optionadalah penggantian flag dengannameyang selalu ditetapkan keflag-valuedanvalueditetapkan kenamespace/aconfigPackage.flagName=true|false.
Membuat modul pengujian berparameter berdasarkan status flag
Untuk membuat modul pengujian berparameter berdasarkan status flag:
Sertakan
FeatureFlagTargetPreparerdalam file konfigurasi modul pengujianAndroidTest.xml:<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >Tentukan opsi nilai flag di bagian
test_module_configdari file buildAndroid.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"}, ], }Kolom
optionsberisi penggantian flag dengannameyang selalu ditetapkan keflag-valuedanvalueditetapkan kenamespace/aconfigPackage.flagName=true|false.
Membuat pengujian unit (Java dan Kotlin)
Bagian ini menjelaskan pendekatan untuk mengganti nilai flag aconfig di tingkat class dan metode (per pengujian) dalam pengujian Java dan Kotlin.
Untuk menulis pengujian unit otomatis dalam codebase besar dengan sejumlah besar tanda, ikuti langkah-langkah berikut:
- Gunakan class
SetFlagsRuledengan anotasi@EnableFlagsdan@DisableFlagsuntuk menguji semua cabang kode. - Gunakan metode
SetFlagsRule.ClassRuleuntuk menghindari bug pengujian umum. - Gunakan
FlagsParameterizationuntuk menguji class Anda di berbagai konfigurasi flag.
Menguji semua cabang kode
Untuk project yang menggunakan class statis untuk mengakses flag, class helper
SetFlagsRule disediakan untuk mengganti nilai flag. Cuplikan kode berikut menunjukkan cara menyertakan SetFlagsRule dan mengaktifkan beberapa tanda secara bersamaan:
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() {
...
}
Dalam hal ini:
@Ruleadalah anotasi yang digunakan untuk menambahkan dependensi flag-JUnit dari classSetFlagsRule.SetFlagsRuleadalah class helper yang disediakan untuk mengganti nilai tanda. Untuk informasi tentang caraSetFlagsRulemenentukan nilai default, lihat Nilai default perangkat.@EnableFlagsadalah anotasi yang menerima sejumlah nama flag arbitrer. Saat menonaktifkan flag, gunakan@DisableFlags. Anda dapat menerapkan anotasi ini ke metode atau class.
Tetapkan nilai tanda untuk seluruh proses pengujian, dimulai dengan
SetFlagsRule, yang dilakukan sebelum metode penyiapan yang dianotasi dengan @Before
dalam pengujian. Nilai flag kembali ke status sebelumnya saat
SetFlagsRule selesai, yaitu setelah metode penyiapan yang dianotasi @After.
Pastikan tanda ditetapkan dengan benar
Seperti yang disebutkan sebelumnya, SetFlagsRule digunakan dengan anotasi JUnit @Rule, yang berarti bahwa SetFlagsRule tidak dapat memastikan tanda Anda disetel dengan benar selama konstruktor class pengujian, atau metode yang dianotasi @BeforeClass atau @AfterClass.
Untuk memastikan bahwa fixture pengujian dibuat dengan nilai class yang benar, gunakan
metode SetFlagsRule.ClassRule sehingga fixture Anda tidak
dibuat hingga metode penyiapan yang diberi anotasi @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() {
...
}
}
Dengan menambahkan aturan class SetFlagsRule.ClassRule, test_flag_foo_turned_on
gagal sebelum dijalankan saat FLAG_FLAG_FOO dibaca oleh konstruktor
DemoClass.
Jika seluruh class Anda memerlukan pengaktifan tanda, pindahkan anotasi @EnableFlags ke
tingkat class (sebelum deklarasi class). Memindahkan anotasi ke
tingkat class memungkinkan SetFlagsRule.ClassRule memastikan tanda ditetapkan dengan benar
selama konstruktor class pengujian, atau selama metode yang dianotasi @BeforeClass atau
@AfterClass.
Menjalankan pengujian di beberapa konfigurasi tanda
Karena Anda dapat menetapkan nilai tanda per pengujian, Anda juga dapat menggunakan parameterisasi untuk menjalankan pengujian di beberapa konfigurasi tanda:
...
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() {...}
}
Perhatikan bahwa dengan SetFlagsRule, tetapi tanpa parameterisasi, class ini menjalankan
tiga
pengujian (fooLogic, legacyBarLogic, dan newBarLogic). Metode fooLogic
berjalan dengan nilai FLAG_FOO dan FLAG_BAR yang ditetapkan di
perangkat.
Saat parameterisasi ditambahkan, metode FlagsParameterization.allCombinationsOf
membuat semua kemungkinan kombinasi flag FLAG_FOO dan FLAG_BAR:
FLAG_FOOadalahtruedanFLAG_BARadalahtrueFLAG_FOOadalahtruedanFLAG_BARadalahfalseFLAG_FOOadalahfalsedanFLAG_BARadalahtrueFLAG_FOOsalah danFLAG_BARadalahfalse
Alih-alih mengubah nilai flag secara langsung, anotasi @DisableFlags dan
@EnableFlags mengubah nilai flag berdasarkan kondisi parameter. Misalnya, legacyBarLogic hanya berjalan saat FLAG_BAR dinonaktifkan, yang terjadi dalam dua dari empat kombinasi tanda. legacyBarLogic dilewati untuk dua kombinasi lainnya.
Ada dua metode untuk membuat parameterisasi untuk tanda Anda:
FlagsParameterization.allCombinationsOf(String...)menjalankan 2^n kali setiap pengujian. Misalnya, satu tanda menjalankan pengujian 2x atau empat tanda menjalankan pengujian 16x.FlagsParameterization.progressionOf(String...)mengeksekusi n+1 eksekusi setiap pengujian. Misalnya, satu tanda menjalankan pengujian 2x dan empat tanda menjalankan pengujian 5x.
Membuat pengujian unit (C dan C++)
AOSP menyertakan makro nilai tanda untuk pengujian C dan C++ yang ditulis dalam framework GoogleTest.
Dalam sumber pengujian, sertakan definisi makro dan library yang dibuat aconfig:
#include <flag_macros.h> #include "android_cts_flags.h"Di sumber pengujian, alih-alih menggunakan makro
TESTdanTESTFuntuk kasus pengujian, gunakanTEST_WITH_FLAGSdanTEST_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"); }Dalam hal ini:
- Makro
TEST_WITH_FLAGSdanTEST_F_WITH_FLAGSdigunakan, bukan makroTESTdanTEST_F. REQUIRES_FLAGS_ENABLEDmenentukan serangkaian tanda rilis fitur yang harus memenuhi kondisi yang diaktifkan. Anda dapat menulis flag ini dalam makroACONFIG_FLAGatauLEGACY_FLAG.REQUIRES_FLAGS_DISABLEDmenentukan serangkaian tanda fitur yang harus memenuhi kondisi dinonaktifkan. Anda dapat menulis flag ini dalam makroACONFIG_FLAGatauLEGACY_FLAG.ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag)adalah makro yang digunakan untuk tanda yang ditentukan dalam file konfigurasi. Makro ini menerima namespace (TEST_NS) dan nama tanda (readwrite_enabled_flag).LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag)adalah makro yang digunakan untuk flag yang ditetapkan dalam konfigurasi perangkat secara default.
- Makro
Dalam file build
Android.bp, tambahkan library yang dihasilkan aconfig dan library makro yang relevan sebagai dependensi pengujian: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"], ... }Jalankan pengujian secara lokal dengan perintah ini:
atest FlagMacrosTestsJika tanda
my_namespace.android.myflag.tests.my_flagdinonaktifkan, hasil pengujiannya adalah:[1/2] MyTest#test1: IGNORED (0ms) [2/2] MyTestF#test2: PASSED (0ms)Jika tanda
my_namespace.android.myflag.tests.my_flagdiaktifkan, hasil pengujiannya adalah:[1/2] MyTest#test1: PASSED (0ms) [2/2] MyTestF#test2: IGNORED (0ms)
Membuat pengujian unit atau menyeluruh yang nilai flag-nya tidak berubah
Untuk kasus pengujian yang tidak dapat mengganti tanda dan hanya dapat memfilter pengujian jika didasarkan pada status tanda saat ini, gunakan aturan CheckFlagsRule dengan anotasi RequiresFlagsEnabled dan RequiresFlagsDisabled.
Langkah-langkah berikut menunjukkan cara membuat dan menjalankan pengujian unit atau end-to-end yang nilai flag-nya tidak dapat diganti:
Di kode pengujian, gunakan
CheckFlagsRuleuntuk menerapkan pemfilteran pengujian. Selain itu, gunakan anotasi JavaRequiresFlagsEnableddanRequiredFlagsDisableduntuk menentukan persyaratan tanda untuk pengujian Anda.Pengujian sisi perangkat menggunakan class
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() {} }Pengujian sisi host menggunakan class
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() {} }Tambahkan
jflag-unitdan library yang dibuat aconfig ke bagianstatic_libsfile build untuk pengujian Anda:android_test { name: "FlagAnnotationTests", srcs: ["*.java"], static_libs: [ "androidx.test.rules", "my_aconfig_lib", "flag-junit", "platform-test-annotations", ], test_suites: ["general-tests"], }Gunakan perintah berikut untuk menjalankan pengujian secara lokal:
atest FlagAnnotationTestsJika tanda
Flags.FLAG_FLAG_NAME_1dinonaktifkan, hasil pengujiannya adalah:[1/2] com.cts.flags.FlagAnnotationTest#test1: ASSUMPTION_FAILED (10ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: PASSED (2ms)Jika tidak, hasil pengujiannya adalah:
[1/2] com.cts.flags.FlagAnnotationTest#test1: PASSED (2ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: ASSUMPTION_FAILED (10ms)
Nilai default perangkat
SetFlagsRule yang diinisialisasi menggunakan nilai tanda dari perangkat. Jika nilai flag di perangkat tidak diganti, seperti dengan adb, maka nilai defaultnya sama dengan konfigurasi rilis build. Jika nilai di perangkat telah diganti, SetFlagsRule akan menggunakan nilai pengganti sebagai default.
Jika pengujian yang sama dijalankan dengan konfigurasi rilis yang berbeda, nilai flag yang tidak ditetapkan secara eksplisit dengan SetFlagsRule dapat bervariasi.
Setelah setiap pengujian, SetFlagsRule memulihkan instance FeatureFlags di Flags
ke FeatureFlagsImpl aslinya, sehingga tidak memiliki efek samping pada
metode dan class pengujian lainnya.