简体   繁体   English

Mockito 用处理器测试 class

[英]Mockito tests for class with Handler

I'm a new one in android dev, so I have an app which contain viewPager with 2 UI fragments and 1 nonUIFragment in which operations are performed (i used "setRetainInstance(true)", it deprecated, but i must use it).我是 android dev 中的新人,所以我有一个包含 viewPager 的应用程序,其中包含 2 个 UI 片段和 1 个执行操作的非 UIFragment(我使用了“setRetainInstance(true)”,它已弃用,但我必须使用它)。 In this nonUIFragment i have Handler which accepts messages from operations started with ExecutorServices.在这个 nonUIFragment 中,我有 Handler,它接受来自 ExecutorServices 开始的操作的消息。 But now my task is test this app with Mockito and i'm totaly confused.但现在我的任务是用 Mockito 测试这个应用程序,我完全糊涂了。

Mentor said "you have to mock the operation that produces the result, is performed in a nonUIFragment, and its result is stored in a collection." Mentor 说“您必须模拟产生结果的操作,在非 UIFragment 中执行,并将其结果存储在集合中。”

How must look this test, I can't create spy() class NonUIFragment and use real methods because of "Method getMainLooper in android.os.Looper not mocked."必须如何看待这个测试,我无法创建spy() class NonUIFragment 并使用真实方法,因为“android.os.Looper 中的方法 getMainLooper 未模拟。” All of my methods are void, they don't returne something, how can i trace this chain.我所有的方法都是无效的,他们不返回任何东西,我怎么能追踪这个链。

NonUIFragment.java NonUIFragment.java

private NonUIToActivityInterface nonUIInterface;
    private final Map<DefOperandTags, HashMap<DefOperationTags, String>> allResultsMap
        = new HashMap<>();

 @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

//Handler pass result to here
    public void passAndSaveResult(DefOperandTags operandTag, DefOperationTags operationTag, String result) {
        allResultsMap.get(operandTag)).put(operationTag, result);
    }

private final Handler handler = new Handler(Looper.getMainLooper()) {
        public void handleMessage(Message msg) {
            if (msg.what != null)
                passAndSaveResult(defOperandTags, defOperationTag, msg.obj.toString());
    };

OneOfOperation.java (add value to the List) OneOfOperation.java(将值添加到列表中)

public class AddToStartList extends Operation {

    public AddToStartList(List list, DefOperationTags operationTag) {
        super(list);
        key = operationTag;
    }

    @Override
    public void operation(Object collection) {
        ((List)collection).add(0, "123");
    }

So, how can I implement what my mentor said?那么,我该如何执行我的导师所说的呢?

This is going to be tricky, because your Android testing library has no implementations , and static methods are generally more difficult to mock safely and effectively.这会很棘手,因为您的 Android 测试库没有实现,而且 static 方法通常更难以安全有效地模拟。

Recent versions of Mockito have added the ability to mock static methods without using another library like PowerMock , so the first choice would be something like that.最新版本的 Mockito 增加了模拟 static 方法的能力,而无需使用像PowerMock这样的另一个库,所以第一选择就是这样。 If at all possible, use mockStatic on Looper::getMainLooper to mock.如果可能的话,在Looper::getMainLooper上使用mockStatic来模拟。

Another solution is to add some indirection, giving you a testing seam:另一种解决方案是添加一些间接性,为您提供测试接缝:

public class NonUIFragment extends Fragment {
  /** Visible for testing. */
  static Looper overrideLooper;

  // ...

  private final Handler handler = new Handler(
      overrideLooper != null ? overrideLooper : Looper.getMainLooper()) {
    /* ... */
  };
}

Finally, if you find yourself doing this kind of mock a lot, you can consider a library like Robolectric .最后,如果你发现自己经常做这种模拟,你可以考虑像Robolectric这样的库。 Using Robolectric you could simulate the looper with a ShadowLooper , which would let you remote-control it, while using Mockito for any classes your team has written.使用 Robolectric,您可以使用ShadowLooper 模拟Looper,这可以让您远程控制它,同时将 Mockito 用于您的团队编写的任何类。 This would prevent you from having to mock a realistic Looper for every test, for instance.例如,这将防止您不得不为每个测试模拟一个真实的 Looper。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM