Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 可以用浓缩咖啡吗;是否等待某个视图出现?_Java_Android_Automated Tests_Android Espresso - Fatal编程技术网

Java 可以用浓缩咖啡吗;是否等待某个视图出现?

Java 可以用浓缩咖啡吗;是否等待某个视图出现?,java,android,automated-tests,android-espresso,Java,Android,Automated Tests,Android Espresso,在我的测试中,我有一个阶段,在按下按钮后,应用程序对云服务执行大量异步计算和请求,然后显示特定视图 是否可以使用Espresso的IdlingResource实现等待某个视图出现 我读过一篇文章,其中的答案和评论似乎建议您可以使用IdlingResource,但我不明白如何使用。Espresso似乎没有任何内置的方式来处理长时间的操作,但必须编写自己的等待循环感觉像是一个黑客 有什么办法可以解决这个问题,或者我应该按照链接中的答案去做 您的IdlingResource可能如下所示: import

在我的测试中,我有一个阶段,在按下按钮后,应用程序对云服务执行大量异步计算和请求,然后显示特定视图

是否可以使用Espresso的
IdlingResource
实现等待某个视图出现

我读过一篇文章,其中的答案和评论似乎建议您可以使用
IdlingResource
,但我不明白如何使用。Espresso似乎没有任何内置的方式来处理长时间的操作,但必须编写自己的等待循环感觉像是一个黑客


有什么办法可以解决这个问题,或者我应该按照链接中的答案去做

您的IdlingResource可能如下所示:

import android.support.test.espresso.IdlingResource;
import android.support.test.espresso.ViewFinder;
import android.support.test.espresso.ViewInteraction;
import android.view.View;

import org.hamcrest.Matcher;

import java.lang.reflect.Field;

import static android.support.test.espresso.Espresso.onView;

public class ViewShownIdlingResource implements IdlingResource {

    private static final String TAG = ViewShownIdlingResource.class.getSimpleName();

    private final Matcher<View> viewMatcher;
    private ResourceCallback resourceCallback;

    public ViewShownIdlingResource(final Matcher<View> viewMatcher) {
        this.viewMatcher = viewMatcher;
    }

    @Override
    public boolean isIdleNow() {
        View view = getView(viewMatcher);
        boolean idle = view == null || view.isShown();

        if (idle && resourceCallback != null) {
            resourceCallback.onTransitionToIdle();
        }

        return idle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        this.resourceCallback = resourceCallback;
    }

    @Override
    public String getName() {
        return this + viewMatcher.toString();
    }

    private static View getView(Matcher<View> viewMatcher) {
        try {
            ViewInteraction viewInteraction = onView(viewMatcher);
            Field finderField = viewInteraction.getClass().getDeclaredField("viewFinder");
            finderField.setAccessible(true);
            ViewFinder finder = (ViewFinder) finderField.get(viewInteraction);
            return finder.getView();
        } catch (Exception e) {
            return null;
        }
    }
}
导入android.support.test.espresso.IdlingResource;
导入android.support.test.espresso.ViewFinder;
导入android.support.test.espresso.ViewInteraction;
导入android.view.view;
导入org.hamcrest.Matcher;
导入java.lang.reflect.Field;
导入静态android.support.test.espresso.espresso.onView;
公共类ViewShownIdlingResource实现IdlingResource{
私有静态最终字符串标记=ViewShownIdlingResource.class.getSimpleName();
私有最终匹配器查看匹配器;
私有资源回调;
公共ViewShownIdlingResource(最终匹配器viewMatcher){
this.viewMatcher=viewMatcher;
}
@凌驾
公共布尔值isIdleNow(){
视图=getView(viewMatcher);
布尔idle=view==null | | view.isShown();
if(空闲和资源回调!=null){
resourceCallback.onTransitionToIdle();
}
返回空闲状态;
}
@凌驾
公共无效RegisterIDletionCallback(ResourceCallback ResourceCallback){
this.resourceCallback=resourceCallback;
}
@凌驾
公共字符串getName(){
返回此+viewMatcher.toString();
}
私有静态视图getView(匹配器视图匹配器){
试一试{
ViewInteraction ViewInteraction=onView(viewMatcher);
Field finderField=viewInteraction.getClass().getDeclaredField(“取景器”);
setAccessible(true);
取景器=(取景器)finderField.get(取景器交互);
返回finder.getView();
}捕获(例外e){
返回null;
}
}
}
然后,您可以创建一个等待查看的助手方法:

public void waitViewShown(Matcher<View> matcher) {
    IdlingResource idlingResource = new ViewShownIdlingResource(matcher);///
    try {
        IdlingRegistry.getInstance().register(idlingResource);
        onView(matcher).check(matches(isDisplayed()));  
    } finally {
        IdlingRegistry.getInstance().unregister(idlingResource);
    }    
}
public void waitview显示(匹配器匹配器){
IdlingResource IdlingResource=新视图显示NidlingResource(匹配器)///
试一试{
IdlingRegistry.getInstance().register(idlingResource);
onView(matcher).检查(匹配项(isDisplayed());
}最后{
IdlingRegistry.getInstance().unregister(idlingResource);
}    
}
最后,在您的测试中:

@Test
public void someTest() {
    waitViewShown(withId(R.id.<some>));

    //do whatever verification needed afterwards    
} 
@测试
公共测试(){
显示的WaitView(带id(R.id.));
//做任何事后需要的验证
} 

您可以通过让IdlingResource等待任何条件来改进此示例,而不仅仅是可见性条件。

我从Anatolii获得了灵感,但没有使用View.class中的方法。我仍然只使用ViewMatchers

/**
 * {@link IdlingResource} that idles until a {@link View} condition is fulfilled.
 */
public class ViewIdlingResource implements IdlingResource {

    private final Matcher<View>    viewMatcher;
    private final Matcher<View>    idleMatcher;
    private       ResourceCallback resourceCallback;

    /**
     * Constructor.
     *
     * @param viewMatcher The matcher to find the view.
     * @param idlerMatcher The matcher condition to be fulfilled to be considered idle.
     */
    public ViewIdlingResource(final Matcher<View> viewMatcher, Matcher<View> idlerMatcher) {
        this.viewMatcher = viewMatcher;
        this.idleMatcher = idlerMatcher;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isIdleNow() {
        View view = getView(viewMatcher);
        boolean isIdle = idleMatcher.matches(view);

        if (isIdle && resourceCallback != null) {
            resourceCallback.onTransitionToIdle();
        }

        return isIdle;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        this.resourceCallback = resourceCallback;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getName() {
        return this + viewMatcher.toString();
    }

    /**
     * Tries to find the view associated with the given {@link Matcher<View>}.
     */
    private static View getView(Matcher<View> viewMatcher) {
        try {
            ViewInteraction viewInteraction = onView(viewMatcher);
            Field finderField = viewInteraction.getClass().getDeclaredField("viewFinder");
            finderField.setAccessible(true);
            ViewFinder finder = (ViewFinder) finderField.get(viewInteraction);
            return finder.getView();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
/**
*{@link IdlingResource}在满足{@link View}条件之前一直处于空闲状态。
*/
公共类ViewIdlingResource实现IdlingResource{
私有最终匹配器查看匹配器;
专用最终匹配器idleMatcher;
私有资源回调;
/**
*构造器。
*
*@param viewMatcher查找视图的匹配器。
*@param idlerMatcher要满足的匹配器条件被视为空闲。
*/
公共视图IDlingResource(最终匹配器viewMatcher、匹配器idlerMatcher){
this.viewMatcher=viewMatcher;
this.idleMatcher=idlerMatcher;
}
/**
*{@inheritardoc}
*/
@凌驾
公共布尔值isIdleNow(){
视图=getView(viewMatcher);
布尔isIdle=idleMatcher.matches(视图);
if(isIdle&&resourceCallback!=null){
resourceCallback.onTransitionToIdle();
}
返回isIdle;
}
/**
*{@inheritardoc}
*/
@凌驾
公共无效RegisterIDletionCallback(ResourceCallback ResourceCallback){
this.resourceCallback=resourceCallback;
}
/**
*{@inheritardoc}
*/
@凌驾
公共字符串getName(){
返回此+viewMatcher.toString();
}
/**
*尝试查找与给定{@link Matcher}关联的视图。
*/
私有静态视图getView(匹配器视图匹配器){
试一试{
ViewInteraction ViewInteraction=onView(viewMatcher);
Field finderField=viewInteraction.getClass().getDeclaredField(“取景器”);
setAccessible(true);
取景器=(取景器)finderField.get(取景器交互);
返回finder.getView();
}捕获(例外e){
抛出新的运行时异常(e);
}
}
}
以及如何在测试用例中使用引导轮,我通过ViewMatchers.isDisplayed()作为引导轮中的预期条件

private void waitUntilViewIsDisplayed(Matcher<View> matcher) {
        IdlingResource idlingResource = new ViewIdlingResource(matcher, isDisplayed());
        try {
            IdlingRegistry.getInstance().register(idlingResource);
            // First call to onView is to trigger the idler.
            onView(withId(0)).check(doesNotExist());
        } finally {
            IdlingRegistry.getInstance().unregister(idlingResource);
        }
    }
private void waitUntilViewIsDisplayed(匹配器匹配器){
IdlingResource IdlingResource=新视图IdlingResource(匹配器,isDisplayed());
试一试{
IdlingRegistry.getInstance().register(idlingResource);
//对onView的第一个调用是触发引导轮。
onView(id为(0))。检查(doesNotExist());
}最后{
IdlingRegistry.getInstance().unregister(idlingResource);
}
}

有了它,您可以将任何Matcher.class传递给ViewIdlingResource构造函数,使其成为viewMatcher参数找到的视图所需的条件。

Atte Backenhof的解决方案有一个小错误(或者我不知道)
/**
 * @param viewMatcher The matcher to find the view.
 * @param idleMatcher The matcher condition to be fulfilled to be considered idle.
 */
class ViewIdlingResource(
    private val viewMatcher: Matcher<View?>?,
    private val idleMatcher: Matcher<View?>?
) : IdlingResource {

    private var resourceCallback: IdlingResource.ResourceCallback? = null

    /**
     * {@inheritDoc}
     */
    override fun isIdleNow(): Boolean {
        val view: View? = getView(viewMatcher)
        val isIdle: Boolean = idleMatcher?.matches(view) ?: false
        if (isIdle) {
            resourceCallback?.onTransitionToIdle()
        }
        return isIdle
    }

    /**
     * {@inheritDoc}
     */
    override fun registerIdleTransitionCallback(resourceCallback: IdlingResource.ResourceCallback?) {
        this.resourceCallback = resourceCallback
    }

    /**
     * {@inheritDoc}
     */
    override fun getName(): String? {
        return "$this ${viewMatcher.toString()}"
    }

    /**
     * Tries to find the view associated with the given [<].
     */
    private fun getView(viewMatcher: Matcher<View?>?): View? {
        return try {
            val viewInteraction = onView(viewMatcher)
            val finderField: Field? = viewInteraction.javaClass.getDeclaredField("viewFinder")
            finderField?.isAccessible = true
            val finder = finderField?.get(viewInteraction) as ViewFinder
            finder.view
        } catch (e: Exception) {
            null
        }
    }

}

/**
 * Waits for a matching View or throws an error if it's taking too long.
 */
fun waitUntilViewIsDisplayed(matcher: Matcher<View?>) {
    val idlingResource: IdlingResource = ViewIdlingResource(matcher, isDisplayed())
    try {
        IdlingRegistry.getInstance().register(idlingResource)
        // First call to onView is to trigger the idler.
        onView(withId(0)).check(doesNotExist())
    } finally {
        IdlingRegistry.getInstance().unregister(idlingResource)
    }
}
    @Test
    fun testUiNavigation() {
        ...
        some initial logic, navigates to a new view
        ...
        waitUntilViewIsDisplayed(withId(R.id.view_to_wait_for))
        ...
        logic on the view that we waited for
        ...
    }
    private const val sleepTime = 1000L
    private const val maximumWaitedTime = 10000L // maximum waited time in milliseconds to wait a view visible

    fun waitViewVisible(viewInteraction: ViewInteraction?, block: (() -> Unit)? = null) {
        waitAssertView(viewInteraction, ViewAssertions.matches(isDisplayed()), block)
    }

    fun waitViewGone(viewInteraction: ViewInteraction?, block: (() -> Unit)? = null) {
        waitAssertView(viewInteraction, ViewAssertions.matches(not(isDisplayed())), block)
    }

    fun waitAssertView(viewInteraction: ViewInteraction?, assertion: ViewAssertion?, block: (() -> Unit)? = null) {
            if (viewInteraction == null || assertion == null) throw NullPointerException()
            val startedTime: Long = System.currentTimeMillis()
            var elapsedTime: Long = 0
            var isVisible = false
            do {
                isVisible = runCatching {
                    viewInteraction.check(assertion)
                }.isSuccess
                if (isVisible) break
                Thread.sleep(sleepTime)
                elapsedTime = System.currentTimeMillis() - startedTime
            } while (elapsedTime <= maximumWaitedTime)
            if (!isVisible) throw TimeoutException("Waited time exceed the maximum waited time")

            block?.invoke()
        }