监控 Picasso 在 Espresso 中的 IdlingResource

Posted

技术标签:

【中文标题】监控 Picasso 在 Espresso 中的 IdlingResource【英文标题】:Monitoring Picasso for IdlingResource in Espresso 【发布时间】:2015-09-25 09:53:43 【问题描述】:

我希望能够将Espresso 监视Picasso 作为IdlingResource,以便在成功加载图像后我可以运行ViewMatchers。

通过浏览Picasso 源代码,我不明白为什么这不起作用。这是我尝试过的:

Picasso picasso = new Picasso.Builder(context).build();
Field dispatcherField = Picasso.class.getDeclaredField("dispatcher");
dispatcherField.setAccessible(true);

try 
  Dispatcher dispatcher = (Dispatcher) dispatcherField.get(picasso);
  Espresso.registerLooperAsIdlingResource(dispatcher.dispatcherThread.getLooper());
 catch (NoSuchFieldException e) 
  throw new PicassoHasBeenRefactoredException();
 catch (Exception e) 
  e.printStackTrace();


onView(withId(R.id.image_view)).check(matches(withImage(R.drawable.drawable)));

(是的,我知道,反射很恶心,但我找不到其他方法来处理Looper

但是在尝试从ImageView获取Bitmap时会导致这个错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.Bitmap android.graphics.drawable.BitmapDrawable.getBitmap()' on a null object reference

为了检查加载图像后测试是否按预期运行,我尝试引入Thread.sleep(1000) 代替IdlingResource 检查并通过了。

假设 IdlingResource 没有正确设置是否安全,更重要的是,在使用 Espresso 检查视图之前等待 Picasso 完成加载的正确方法是什么?

【问题讨论】:

你不能使用 Picasso 的 onSucess callback 来设置你的 IdelingResource 吗? @RahulTiwari 我不想修改任何生产代码来适应测试,除非你的意思是别的? 我说的是使用 Picasso 提供的回调函数 onSuccessonError 并尽可能摆脱反射。所以是的,我说的是修改代码,但它肯定不会影响任何功能。 这是一个权衡。在我看来,在生产代码上设置一个 idlingResource 是非常无害的,并且会引导您获得更简单的测试代码。 【参考方案1】:

我正在使用 IdlingResource 检查是否还有操作​​。

请注意,IdlingResource 必须与 Picasso 位于同一包中才能访问受包保护的变量

package com.squareup.picasso;

public class PicassoIdlingResource implements IdlingResource, ActivityLifecycleCallback 
  protected ResourceCallback callback;

  WeakReference<Picasso> picassoWeakReference;

  @Override
  public String getName() 
    return "PicassoIdlingResource";
  

  @Override
  public boolean isIdleNow() 
    if (isIdle()) 
      notifyDone();
      return true;
     else 
      return false;
    
  

  public boolean isIdle() 
    return picassoWeakReference == null
            || picassoWeakReference.get() == null
            || picassoWeakReference.get().targetToAction.isEmpty();
  

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

  void notifyDone() 
    if (callback != null) 
      callback.onTransitionToIdle();
    
  

  @Override
  public void onActivityLifecycleChanged(Activity activity, Stage stage) 
    switch (stage) 
      case CREATED:
        picassoWeakReference = new WeakReference<>(Picasso.with(activity));
        break;
      case STOPPED:
        // Clean up reference
        picassoWeakReference = null;
        break;
      default: // NOP
    
  

我认为不需要使用 Wea​​kReference,但也没有什么坏处。

另外,我发现了一种情况,它不等到毕加索完成(使用 .load(null) 时)。因此,使用风险自负,如果您改进它,请回来。

查看要点了解完整的详细信息和用法 (https://gist.github.com/Maragues/0c0db81a137c8d067396)

【讨论】:

谢谢!在活动之间移动时,该解决方案无法正常工作。为了解决这个问题,我将状态 CREATED & STOPPED 替换为 RESUMED & PAUSED 我还发现这会引入很大的延迟(每个加载的图像最多延迟 5 秒),因为 Espresso 在重新检查之间有几秒钟的延迟。解决方案是强制重新检查 PicassoIdlingResource,如下例所示:gist.github.com/vaughandroid/… 谢谢@SebasLG,我目前正在处理另一个项目,但一旦我回到旧代码,我会检查你的代码。

以上是关于监控 Picasso 在 Espresso 中的 IdlingResource的主要内容,如果未能解决你的问题,请参考以下文章

Android Picasso图片加载库源码剖析

Picasso中的缓存无效

如何与 Espresso 中的 alertdialog 交互?

Android Studio 2.2 中的 Espresso 测试录制功能

Kotlin 中的 Espresso 正则表达式匹配器 [重复]

Espresso 不使用 Gif 动画运行 Activity 测试