Khi ra mắt cờ khởi chạy tính năng, bạn phải tuân thủ các chính sách kiểm thử mới:
- Quy trình kiểm thử của bạn phải bao gồm cả hành vi bật và tắt của cờ.
- Bạn phải sử dụng các cơ chế chính thức để đặt giá trị gắn cờ trong quá trình thử nghiệm.
- Kiểm thử xTS không được ghi đè các giá trị cờ trong kiểm thử.
Phần tiếp theo sẽ cung cấp các cơ chế chính thức mà bạn phải sử dụng để tuân thủ các chính sách này.
Kiểm tra mã bị gắn cờ của bạn
Tình huống kiểm thử | Cơ chế được sử dụng |
---|---|
Kiểm thử cục bộ khi các giá trị gắn cờ thay đổi thường xuyên | Cầu gỡ lỗi Android như đã thảo luận trong phần Thay đổi giá trị của cờ trong thời gian chạy |
Kiểm thử cục bộ khi các giá trị gắn cờ không thường xuyên thay đổi | Tệp giá trị cờ như đã thảo luận trong phần Đặt giá trị cờ phát hành tính năng |
Kiểm thử toàn diện khi giá trị của cờ thay đổi | FeatureFlagTargetPreparer như đã thảo luận trong phần Tạo kiểm thử toàn diện |
Kiểm thử đơn vị khi giá trị cờ thay đổi | SetFlagsRule với @EnableFlags và @DisableFlags như đã thảo luận trong phần Tạo kiểm thử đơn vị (Java và Kotlin) hoặc Tạo kiểm thử đơn vị (C và C++) |
Kiểm thử toàn diện hoặc kiểm thử đơn vị mà giá trị cờ không thể thay đổi | CheckFlagsRule như đã thảo luận trong bài viết Tạo các bài kiểm thử toàn diện hoặc kiểm thử đơn vị trong đó các giá trị gắn cờ không thay đổi |
Tạo chương trình kiểm thử toàn diện
AOSP cung cấp một lớp có tên là FeatureFlagTargetPreparer
, cho phép kiểm thử toàn diện trên thiết bị. Lớp này chấp nhận các cơ chế ghi đè giá trị cờ làm dữ liệu đầu vào, đặt những cờ đó trong cấu hình thiết bị trước khi thực thi kiểm thử và khôi phục cờ sau khi thực thi.
Bạn có thể áp dụng chức năng của lớp FeatureFlagTargetPreparer
ở mô-đun kiểm thử và các cấp cấu hình kiểm thử.
Áp dụng FeatureflagTargetIdr trong cấu hình mô-đun kiểm thử
Để áp dụng FeatureFlagTargetPreparer
trong cấu hình mô-đun kiểm thử, hãy đưa FeatureFlagTargetPreparer
và giá trị cờ ghi đè vào tệp cấu hình mô-đun kiểm thử 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>
Trong trường hợp:
target.preparer class
luôn được đặt thànhcom.android.tradefed.targetprep.FeatureFlagTargetPreparer
.option
là chế độ ghi đè cờ, trong đóname
luôn được đặt thànhflag-value
vàvalue
được đặt thànhnamespace/aconfigPackage.flagName=true|false
.
Tạo các mô-đun kiểm thử có tham số dựa trên trạng thái cờ
Cách tạo các mô-đun kiểm thử có tham số dựa trên trạng thái cờ:
Đưa
FeatureFlagTargetPreparer
vào tệp cấu hình mô-đun kiểm thửAndroidTest.xml
:<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >
Chỉ định các tuỳ chọn giá trị gắn cờ trong phần
test_module_config
của tệp bản dựngAndroid.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"}, ], }
Trường
options
chứa các chế độ ghi đè cờ, trong đóname
luôn được đặt thànhflag-value
vàvalue
được đặt thànhnamespace/aconfigPackage.flagName=true|false
.
Tạo bài kiểm thử đơn vị (Java và Kotlin)
Phần này mô tả phương pháp ghi đè các giá trị cờ aconfig ở cấp lớp và cấp phương thức (mỗi lần kiểm thử) trong các kiểm thử Java và Kotlin.
Để viết kiểm thử đơn vị tự động trong một cơ sở mã lớn có số lượng lớn cờ, hãy làm theo các bước sau:
- Sử dụng lớp
SetFlagsRule
có chú giải@EnableFlags
và@DisableFlags
để kiểm thử tất cả các nhánh mã. - Sử dụng phương thức
SetFlagsRule.ClassRule
để tránh các lỗi kiểm thử thường gặp. - Sử dụng
FlagsParameterization
để kiểm thử các lớp của bạn trên một loạt các cấu hình cờ.
Kiểm thử tất cả các nhánh mã
Đối với các dự án sử dụng lớp tĩnh để truy cập vào cờ, lớp trợ giúp SetFlagsRule
sẽ được cung cấp để ghi đè các giá trị cờ. Đoạn mã sau đây cho biết cách đưa SetFlagsRule
vào và bật một số cờ cùng một lúc:
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() {
...
}
Trong trường hợp:
@Rule
là chú giải dùng để thêm phần phụ thuộc cờ-JUnit của lớpSetFlagsRule
.SetFlagsRule
là lớp trợ giúp được cung cấp để ghi đè các giá trị cờ. Để biết thông tin về cáchSetFlagsRule
xác định giá trị mặc định, hãy xem bài viết Giá trị mặc định của thiết bị.@EnableFlags
là một chú giải chấp nhận số lượng tên cờ tuỳ ý. Khi tắt cờ, hãy sử dụng@DisableFlags
. Bạn có thể áp dụng các chú giải này cho một phương thức hoặc một lớp.
Đặt các giá trị cờ cho toàn bộ quy trình kiểm thử, bắt đầu bằng SetFlagsRule
, trước mọi phương thức thiết lập có chú thích @Before
trong quá trình kiểm thử. Các giá trị gắn cờ sẽ trở về trạng thái trước đó khi SetFlagsRule
kết thúc, tức là sau mọi phương thức thiết lập có chú thích @After
.
Đảm bảo cờ được đặt chính xác
Như đã đề cập trước đó, SetFlagsRule
được dùng cùng với chú giải @Rule
của JUnit, tức là SetFlagsRule
không thể đảm bảo cờ của bạn được đặt chính xác trong hàm khởi tạo của lớp kiểm thử, hoặc bất kỳ phương thức nào có chú giải @BeforeClass
hay @AfterClass
.
Để đảm bảo rằng các môi trường thử nghiệm cố định được tạo bằng giá trị lớp chính xác, hãy sử dụng phương thức SetFlagsRule.ClassRule
để các môi trường thử nghiệm cố định không được tạo cho đến khi có phương thức thiết lập được chú thích @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() {
...
}
}
Bằng cách thêm quy tắc lớp SetFlagsRule.ClassRule
, test_flag_foo_turned_on
sẽ không thành công trước khi chạy khi FLAG_FLAG_FOO
được hàm khởi tạo của DemoClass
đọc.
Nếu toàn bộ lớp của bạn cần bật cờ, hãy chuyển chú thích @EnableFlags
sang cấp lớp (trước phần khai báo lớp). Việc di chuyển chú giải đến cấp lớp cho phép SetFlagsRule.ClassRule
đảm bảo cờ được đặt chính xác trong hàm khởi tạo của lớp kiểm thử hoặc trong bất kỳ phương thức nào có chú thích @BeforeClass
hoặc @AfterClass
.
Chạy kiểm thử trên nhiều cấu hình cờ
Vì có thể đặt giá trị gắn cờ cho mỗi lần kiểm thử, nên bạn cũng có thể sử dụng tính năng tham số hoá để chạy kiểm thử trên nhiều cấu hình cờ:
...
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() {...}
}
Xin lưu ý rằng với SetFlagsRule
, nhưng không có tham số, lớp này sẽ chạy 3 bài kiểm thử (fooLogic
, legacyBarLogic
và newBarLogic
). Phương thức fooLogic
sẽ chạy với bất kỳ giá trị nào của FLAG_FOO
và FLAG_BAR
được đặt trên thiết bị.
Khi thêm tham số, phương thức FlagsParameterization.allCombinationsOf
sẽ tạo tất cả các tổ hợp cờ FLAG_FOO
và FLAG_BAR
có thể có:
FLAG_FOO
làtrue
vàFLAG_BAR
làtrue
FLAG_FOO
làtrue
vàFLAG_BAR
làfalse
FLAG_FOO
làfalse
vàFLAG_BAR
làtrue
FLAG_FOO
là false vàFLAG_BAR
làfalse
Thay vì trực tiếp thay đổi giá trị cờ, chú thích @DisableFlags
và @EnableFlags
sẽ sửa đổi giá trị cờ dựa trên điều kiện tham số. Ví dụ: legacyBarLogic
chỉ chạy khi FLAG_BAR
bị tắt, điều này xảy ra trong hai trong số bốn tổ hợp cờ. legacyBarLogic
sẽ bị bỏ qua đối với hai tổ hợp còn lại.
Có hai phương thức để tạo tham số cho cờ của bạn:
FlagsParameterization.allCombinationsOf(String...)
thực thi 2^n lần chạy của mỗi quy trình kiểm thử. Ví dụ: một cờ chạy kiểm thử 2x hoặc bốn cờ chạy kiểm thử 16x.FlagsParameterization.progressionOf(String...)
thực thi n+1 lần chạy của mỗi bài kiểm thử. Ví dụ: một cờ chạy 2 lần kiểm thử và 4 cờ chạy 5 lần kiểm thử.
Tạo chương trình kiểm thử đơn vị (C và C++)
AOSP bao gồm các macro giá trị gắn cờ cho các kiểm thử C và C++ được viết trong khung GoogleTest.
Trong nguồn kiểm thử của bạn, hãy thêm các định nghĩa macro và thư viện do cấu hình tạo:
#include <flag_macros.h> #include "android_cts_flags.h"
Trong nguồn kiểm thử, thay vì sử dụng macro
TEST
vàTESTF
cho các trường hợp kiểm thử, hãy dùngTEST_WITH_FLAGS
và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"); }
Trong trường hợp:
- Macro
TEST_WITH_FLAGS
vàTEST_F_WITH_FLAGS
được dùng thay cho macroTEST
vàTEST_F
. REQUIRES_FLAGS_ENABLED
xác định một tập hợp cờ phát hành tính năng phải đáp ứng điều kiện bật. Bạn có thể viết các cờ này trong macroACONFIG_FLAG
hoặcLEGACY_FLAG
.REQUIRES_FLAGS_DISABLED
xác định một tập hợp cờ tính năng phải đáp ứng điều kiện bị tắt. Bạn có thể viết các cờ này trong macroACONFIG_FLAG
hoặcLEGACY_FLAG
.ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag)
là một macro dùng cho các cờ được xác định trong tệp aconfig. Macro này chấp nhận một không gian tên (TEST_NS
) và tên cờ (readwrite_enabled_flag
).LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag)
là một macro dùng cho các cờ được đặt trong cấu hình thiết bị theo mặc định.
- Macro
Trong tệp bản dựng
Android.bp
, hãy thêm các thư viện do aconfig tạo và các thư viện macro liên quan làm phần phụ thuộc kiểm thử: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"], ... }
Chạy các chương trình kiểm thử cục bộ bằng lệnh sau:
atest FlagMacrosTests
Nếu cờ
my_namespace.android.myflag.tests.my_flag
bị tắt, thì kết quả kiểm thử sẽ là:[1/2] MyTest#test1: IGNORED (0ms) [2/2] MyTestF#test2: PASSED (0ms)
Nếu cờ
my_namespace.android.myflag.tests.my_flag
được bật, thì kết quả kiểm thử sẽ là:[1/2] MyTest#test1: PASSED (0ms) [2/2] MyTestF#test2: IGNORED (0ms)
Tạo kiểm thử toàn diện hoặc đơn vị mà trong đó các giá trị gắn cờ không thay đổi
Đối với các trường hợp kiểm thử mà bạn không thể ghi đè cờ và chỉ có thể lọc các kiểm thử nếu các kiểm thử đó dựa trên trạng thái cờ hiện tại, hãy sử dụng quy tắc CheckFlagsRule
với chú thích RequiresFlagsEnabled
và RequiresFlagsDisabled
.
Các bước sau đây hướng dẫn bạn cách tạo và chạy kiểm thử toàn diện hoặc kiểm thử đơn vị mà không thể ghi đè các giá trị cờ:
Trong mã kiểm thử, hãy sử dụng
CheckFlagsRule
để áp dụng tính năng lọc kiểm thử. Ngoài ra, hãy sử dụng chú thích JavaRequiresFlagsEnabled
vàRequiredFlagsDisabled
để chỉ định các yêu cầu về cờ cho kiểm thử của bạn.Kiểm thử phía thiết bị sử dụng lớp
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() {} }
Quy trình kiểm thử phía máy chủ sử dụng lớp
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() {} }
Thêm
jflag-unit
và các thư viện do aconfig tạo vào phầnstatic_libs
của tệp bản dựng để kiểm thử:android_test { name: "FlagAnnotationTests", srcs: ["*.java"], static_libs: [ "androidx.test.rules", "my_aconfig_lib", "flag-junit", "platform-test-annotations", ], test_suites: ["general-tests"], }
Sử dụng lệnh sau để chạy kiểm thử cục bộ:
atest FlagAnnotationTests
Nếu cờ
Flags.FLAG_FLAG_NAME_1
bị tắt, kết quả kiểm thử sẽ là:[1/2] com.cts.flags.FlagAnnotationTest#test1: ASSUMPTION_FAILED (10ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: PASSED (2ms)
Nếu không, kết quả kiểm thử sẽ là:
[1/2] com.cts.flags.FlagAnnotationTest#test1: PASSED (2ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: ASSUMPTION_FAILED (10ms)
Giá trị mặc định của thiết bị
SetFlagsRule
đã khởi chạy sử dụng các giá trị cờ từ thiết bị. Nếu giá trị cờ trên thiết bị không bị ghi đè, chẳng hạn như bằng adb, thì giá trị mặc định sẽ giống với cấu hình bản phát hành của bản dựng. Nếu giá trị trên thiết bị đã bị ghi đè, thì SetFlagsRule
sẽ sử dụng giá trị ghi đè làm giá trị mặc định.
Nếu cùng một kiểm thử được thực thi trong nhiều cấu hình bản phát hành, thì giá trị của các cờ không được đặt rõ ràng bằng SetFlagsRule
có thể thay đổi.
Sau mỗi lần kiểm thử, SetFlagsRule
sẽ khôi phục thực thể FeatureFlags
trong Flags
về FeatureFlagsImpl
ban đầu để không có tác dụng phụ đối với các lớp và phương thức kiểm thử khác.