Dengan diperkenalkannya tanda peluncuran fitur, ada kebijakan pengujian baru yang harus Anda patuhi:
- Pengujian Anda harus mencakup perilaku flag yang diaktifkan dan dinonaktifkan.
- Anda harus menggunakan mekanisme resmi untuk menetapkan nilai flag selama pengujian.
- Pengujian xTS tidak boleh mengganti 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 flag sering berubah | Android debug bridge seperti yang dibahas dalam artikel Mengubah nilai flag saat runtime |
Pengujian lokal saat nilai flag tidak sering berubah | File nilai flag seperti yang dibahas dalam Menetapkan nilai flag 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 menyeluruh dengan nilai flag yang tidak dapat berubah | CheckFlagsRule seperti yang dibahas dalam Membuat pengujian unit atau menyeluruh yang nilai flagnya tidak berubah |
Membuat pengujian menyeluruh
AOSP menyediakan class yang disebut FeatureFlagTargetPreparer
, yang memungkinkan
pengujian menyeluruh di perangkat. Class ini menerima penggantian nilai tanda sebagai
input, menetapkan tanda tersebut dalam konfigurasi perangkat sebelum eksekusi uji,
dan memulihkan tanda setelah dieksekusi.
Anda dapat menerapkan fungsi class FeatureFlagTargetPreparer
pada
modul pengujian dan tingkat konfigurasi pengujian.
Menerapkan FeatureFlagTargetPreparer dalam konfigurasi modul pengujian
Untuk menerapkan FeatureFlagTargetPreparer
dalam konfigurasi modul pengujian, sertakan penggantian nilai FeatureFlagTargetPreparer
dan tanda 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 class
selalu ditetapkan kecom.android.tradefed.targetprep.FeatureFlagTargetPreparer
.option
adalah penggantian flag denganname
yang selalu ditetapkan keflag-value
danvalue
ditetapkan kenamespace/aconfigPackage.flagName=true|false
.
Membuat modul pengujian berparameter berdasarkan status flag
Untuk membuat modul pengujian berparameter berdasarkan status tanda:
Sertakan
FeatureFlagTargetPreparer
dalam file konfigurasi modul pengujianAndroidTest.xml
:<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >
Tentukan opsi nilai flag di bagian
test_module_config
pada 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
options
berisi penggantian tanda denganname
yang selalu ditetapkan keflag-value
danvalue
ditetapkan 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-test) dalam pengujian Java dan Kotlin.
Untuk menulis pengujian unit otomatis dalam codebase besar dengan banyak flag, ikuti langkah-langkah berikut:
- Gunakan class
SetFlagsRule
dengan anotasi@EnableFlags
dan@DisableFlags
untuk menguji semua cabang kode. - Gunakan metode
SetFlagsRule.ClassRule
untuk menghindari bug pengujian umum. - Gunakan
FlagsParameterization
untuk menguji class Anda di berbagai konfigurasi flag.
Menguji semua cabang kode
Bagi 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
sekaligus:
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:
@Rule
adalah anotasi yang digunakan untuk menambahkan dependensi flag-JUnit dari classSetFlagsRule
.SetFlagsRule
adalah class bantuan yang disediakan untuk mengganti nilai flag. Untuk mengetahui informasi tentang caraSetFlagsRule
menentukan nilai default, lihat Nilai default perangkat.@EnableFlags
adalah anotasi yang menerima jumlah arbitrer nama flag. Saat menonaktifkan tanda, gunakan@DisableFlags
. Anda dapat menerapkan anotasi ini ke metode atau class.
Tetapkan nilai flag untuk seluruh proses pengujian, dimulai dengan SetFlagsRule
, yang sebelum metode penyiapan beranotasi @Before
apa pun dalam pengujian tersebut. Nilai flag kembali ke status sebelumnya saat
SetFlagsRule
selesai, yaitu setelah metode penyiapan beranotasi @After
.
Memastikan tanda disetel dengan benar
Seperti yang disebutkan sebelumnya, SetFlagsRule
digunakan dengan anotasi @Rule
JUnit, yang berarti
SetFlagsRule
tidak dapat memastikan flag Anda ditetapkan dengan benar selama konstruktor class
pengujian, atau metode beranotasi @BeforeClass
atau @AfterClass
apa pun.
Untuk memastikan bahwa perlengkapan pengujian dibuat dengan nilai class yang benar, gunakan
metode SetFlagsRule.ClassRule
sehingga perlengkapan Anda tidak
dibuat hingga metode penyiapan yang dianotasi @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
akan gagal sebelum berjalan saat FLAG_FLAG_FOO
dibaca oleh konstruktor
DemoClass
.
Jika seluruh class Anda memerlukan flag yang diaktifkan, pindahkan anotasi @EnableFlags
ke
tingkat class (sebelum deklarasi class). Memindahkan anotasi ke
tingkat class memungkinkan SetFlagsRule.ClassRule
memastikan flag ditetapkan dengan benar
selama konstruktor class pengujian, atau selama metode yang dianotasi @BeforeClass
atau
@AfterClass
.
Menjalankan pengujian di beberapa konfigurasi flag
Karena Anda dapat menetapkan nilai flag per pengujian, Anda juga dapat menggunakan parameterisasi untuk menjalankan pengujian di beberapa konfigurasi flag:
...
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
apa pun yang ditetapkan di
perangkat.
Saat parameterisasi ditambahkan, metode FlagsParameterization.allCombinationsOf
akan membuat semua kemungkinan kombinasi dari tanda FLAG_FOO
dan FLAG_BAR
:
FLAG_FOO
adalahtrue
danFLAG_BAR
adalahtrue
FLAG_FOO
adalahtrue
danFLAG_BAR
adalahfalse
FLAG_FOO
adalahfalse
danFLAG_BAR
adalahtrue
FLAG_FOO
salah danFLAG_BAR
adalahfalse
Alih-alih mengubah nilai flag secara langsung, anotasi @DisableFlags
dan
@EnableFlags
mengubah nilai flag berdasarkan kondisi parameter. Misalnya,
legacyBarLogic
hanya berjalan jika FLAG_BAR
dinonaktifkan, yang terjadi dalam
dua dari empat kombinasi flag. legacyBarLogic
dilewati untuk dua kombinasi lainnya.
Ada dua metode untuk membuat parameterisasi untuk flag Anda:
FlagsParameterization.allCombinationsOf(String...)
mengeksekusi 2^n operasi dari setiap pengujian. Misalnya, satu flag menjalankan 2x pengujian atau empat flag menjalankan 16x pengujian.FlagsParameterization.progressionOf(String...)
menjalankan n+1 operasi dari setiap pengujian. Misalnya, satu penanda menjalankan pengujian 2x dan empat penanda 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 dihasilkan aconfig:
#include <flag_macros.h> #include "android_cts_flags.h"
Di sumber pengujian, gunakan
TEST_WITH_FLAGS
danTEST_F_WITH_FLAGS
, bukan makroTEST
danTESTF
untuk kasus pengujian:#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_FLAGS
danTEST_F_WITH_FLAGS
digunakan, bukan makroTEST
danTEST_F
. REQUIRES_FLAGS_ENABLED
menentukan kumpulan tanda rilis fitur yang harus memenuhi kondisi diaktifkan. Anda dapat menulis flag ini dalam makroACONFIG_FLAG
atauLEGACY_FLAG
.REQUIRES_FLAGS_DISABLED
menentukan kumpulan tombol fitur yang harus memenuhi kondisi dinonaktifkan. Anda dapat menulis flag ini dalam makroACONFIG_FLAG
atauLEGACY_FLAG
.ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag)
adalah makro yang digunakan untuk flag yang ditentukan dalam file konfigurasi. Makro ini menerima namespace (TEST_NS
) dan nama flag (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 FlagMacrosTests
Jika tanda
my_namespace.android.myflag.tests.my_flag
dinonaktifkan, hasil pengujiannya adalah:[1/2] MyTest#test1: IGNORED (0ms) [2/2] MyTestF#test2: PASSED (0ms)
Jika tanda
my_namespace.android.myflag.tests.my_flag
diaktifkan, hasil pengujiannya adalah:[1/2] MyTest#test1: PASSED (0ms) [2/2] MyTestF#test2: IGNORED (0ms)
Membuat pengujian unit atau menyeluruh yang nilai flagnya tidak berubah
Untuk kasus pengujian saat Anda tidak dapat mengganti flag dan hanya dapat memfilter pengujian jika
berdasarkan status flag saat ini, gunakan aturan CheckFlagsRule
dengan
anotasi RequiresFlagsEnabled
dan RequiresFlagsDisabled
.
Langkah-langkah berikut menunjukkan cara membuat dan menjalankan pengujian menyeluruh atau unit yang tidak dapat mengganti nilai flag:
Dalam kode pengujian, gunakan
CheckFlagsRule
untuk menerapkan pemfilteran pengujian. Selain itu, gunakan anotasi JavaRequiresFlagsEnabled
danRequiredFlagsDisabled
untuk menentukan persyaratan flag dalam 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-unit
dan library yang dihasilkan aconfig ke bagianstatic_libs
file 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 FlagAnnotationTests
Jika flag
Flags.FLAG_FLAG_NAME_1
dinonaktifkan, 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 tanda di perangkat tidak diganti, seperti dengan adb, nilai
default akan sama
dengan konfigurasi rilis build. Jika nilai di perangkat telah
digantikan, SetFlagsRule
akan menggunakan nilai penggantian sebagai
default.
Jika pengujian yang sama dijalankan dalam konfigurasi rilis yang berbeda, nilai flag yang tidak ditetapkan secara eksplisit dengan SetFlagsRule
dapat bervariasi.
Setelah setiap pengujian, SetFlagsRule
akan memulihkan instance FeatureFlags
di Flags
ke FeatureFlagsImpl
aslinya, sehingga tidak memiliki efek samping pada
metode dan class pengujian lainnya.