我一直在寻找一种方法来单独测试我的碎片的UI(即独立于其他碎片和活动),但我找不到办法。
特别是,我要说我有片段A,片段B和片段C.进入片段C的唯一方法(应用方式)是首先通过片段A和片段B.我正在寻找一种直接测试Fragment C的方法(可能通过模拟它的依赖关系,如果有的话),而不必通过片段A和B。
到目前为止我调查的工具:
monkey:仅用于通过命令行生成伪随机事件。不是我想要的。
monkeyrunner:它可以运行Python程序将事件流发送到我的Android应用程序,但它无法直接使用这些脚本定位特定的片段。
Espresso:白盒测试工具。这接近我想要的,但它仍然需要在到达片段C之前通过片段A和B(即,您需要启动您的应用程序,然后测试将从那里运行)。
UI Automator:黑盒测试工具。这也很接近,但同样需要在测试我想要的片段(片段C)之前通过之前的片段。
有没有办法直接测试Fragmen的UI ?
答案 0 :(得分:50)
我正在使用自定义FragmentTestRule
和Espresso来隔离我的每个Fragments
。
我有一个专门的TestActivity
,可以在我的应用中显示经过测试的Fragments
。在我的情况下,Activity
仅存在于debug
变体中,因为我的检测测试是针对debug
运行的。
TL; DR使用FragmentTestRule下的真棒@brais-gabin 库。
<强> 1。在TestActivity
中创建src/debug/java/your/package/TestActivity.java
,其中包含已将测试Fragment
添加到的内容视图:
@VisibleForTesting
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frameLayout = new FrameLayout(this);
frameLayout.setId(R.id.container);
setContentView(frameLayout);
}
}
<强> 2。为debug
变体创建AndroidManifest.xml 并声明TestActivity
。这是在测试时启动TestActivity
所必需的。将此清单添加到debug
中的src/debug/AndroidManifest.xml
变体:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity android:name="your.package.TestActivity"/>
</application>
</manifest>
第3。在FragmentTestRule
的{{1}}变体中创建androidTest
:
src/androidTest/java/your/test/package/FragmentTestRule.java
<强> 4。然后,您可以单独测试public class FragmentTestRule<F extends Fragment> extends ActivityTestRule<TestActivity> {
private final Class<F> mFragmentClass;
private F mFragment;
public FragmentTestRule(final Class<F> fragmentClass) {
super(TestActivity.class, true, false);
mFragmentClass = fragmentClass;
}
@Override
protected void afterActivityLaunched() {
super.afterActivityLaunched();
getActivity().runOnUiThread(() -> {
try {
//Instantiate and insert the fragment into the container layout
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
mFragment = mFragmentClass.newInstance();
transaction.replace(R.id.container, mFragment);
transaction.commit();
} catch (InstantiationException | IllegalAccessException e) {
Assert.fail(String.format("%s: Could not insert %s into TestActivity: %s",
getClass().getSimpleName(),
mFragmentClass.getSimpleName(),
e.getMessage()));
}
});
}
public F getFragment(){
return mFragment;
}
}
:
Fragments
答案 1 :(得分:2)
我使用FragmentTestRule开发了@thaussma's idea Andorid库。它允许您单独测试Fragment
。
你只需要添加:
@Rule
public FragmentTestRule<?, FragmentWithoutActivityDependency> fragmentTestRule =
FragmentTestRule.create(FragmentWithoutActivityDependency.class);
答案 2 :(得分:1)
您可以使用Robotium。这适用于Android UI测试。
答案 3 :(得分:0)
如果您使用的是Navigation Architecture组件,并且在应用程序中使用的是单一活动架构,则可以通过在测试开始时通过深度链接到目标片段(带有适当的参数)来快速测试每个片段。
。例如:
@Rule
@JvmField
var activityRule = ActivityTestRule(MainActivity::class.java)
protected fun launchFragment(destinationId: Int,
argBundle: Bundle? = null) {
val launchFragmentIntent = buildLaunchFragmentIntent(destinationId, argBundle)
activityRule.launchActivity(launchFragmentIntent)
}
private fun buildLaunchFragmentIntent(destinationId: Int, argBundle: Bundle?): Intent =
NavDeepLinkBuilder(InstrumentationRegistry.getInstrumentation().targetContext)
.setGraph(R.navigation.navigation)
.setComponentName(MainActivity::class.java)
.setDestination(destinationId)
.setArguments(argBundle)
.createTaskStackBuilder().intents[0]
destinationId是导航图中的片段目标ID。这是一个调用示例,一旦您准备启动该片段,便会执行该操作:
launchFragment(R.id.target_fragment, targetBundle())
private fun targetBundle(): Bundle? {
val bundle = Bundle()
bundle.putString(ARGUMENT_ID, "Argument needed by fragment")
return bundle
}
以这种方式进行操作将直接启动片段。如果您的测试有效,则表明片段被深层链接至您的应用程序不会崩溃。它还可以确保如果该进程被系统终止并尝试重建堆栈并重新启动片段,则该应用程序将保持稳定。