【问题标题】:Unit testing a network response. Works when debugging, not when actually running单元测试网络响应。在调试时工作,而不是在实际运行时工作
【发布时间】:2016-08-30 04:14:14
【问题描述】:

我目前正在尝试测试是否确实收到了网络响应。

虽然我知道这不是我在测试方面应该做的事情,但这是我自己的好奇心,如果可能的话,我想继续。

就目前而言,我已经成功创建了测试。请求被毫无问题地发送到排球队列。

现在奇怪的部分:

该请求永远不会执行。这是我如何测试它的想法:

 @Test
    public void testSimpleGetResponseFromServerVolley() throws Exception {
        final CountDownLatch signal = new CountDownLatch(1);

        NetworkClass.NetworkListener listener = new NetworkClass.NetworkListener() {
            @Override
            public void onResponse(Response response) {
                assertThat(response != null);
                System.out.println("Got Response");
                signal.countDown();

            }

            @Override
            public void onError(Throwable error) {
                System.out.println("No Response");
                signal.countDown();
            }
        };
        NetworkClass.getResponseFromServer(null, listener);
        signal.await();
    }

此代码意外导致测试挂起并且永远无法完成。

但是,这就是我不再对情况失去理解的地方:

如果我通过 debug 运行测试并逐行执行,测试成功执行,并收到响应。

我认为正在发生的事情:

当我通过调试单步执行时,volley requestQueue 成功进行并发出请求,并在调用await() 之前收到响应。

当我不通过调试单步执行时,await() 正在阻塞处理所有这些的线程。

关于如何处理这个问题的任何想法?

【问题讨论】:

  • @Test?那是什么?
  • 这是一个 jUnit 测试,正如我的标签所暗示的那样。
  • 如果断言失败,countDown() 永远不会被调用。我不知道 junit 在多线程测试中的行为如何,但我在其他测试框架的情况下看到了奇怪的行为。
  • 不,断言没有失败,测试只是无限期挂起。
  • 尝试使用带有超时的signal.await(),然后查看是否发生超时。这样你就可以确定是否是测试挂起的原因。

标签: android junit mockito android-testing android-networking


【解决方案1】:

Volley 依赖 Looper.getMainLooper() 来处理其执行。使用 RobolectricTestRunner 时,Robolectric 会对此进行模拟,因此无法正确设置,从而导致测试失败。

在我的具体情况下,当我使用断点时,系统实际上确实设置了主循环器,因为系统正在利用它来显示断点/调试工具。因此,这描述了我最初的问题中发现的行为背后的原因。

现在,对于在单元测试期间使用 Volley 获得真实网络响应的解决方案,必须将执行器更改为不使用主循环器。

作为一个简单的解决方案,创建一个依赖于 Executor.singleThreadExecutor() 而不是 Main Looper 的请求队列。

这就是我的意思:

    //Specific test queue that uses a singleThreadExecutor instead of the mainLooper for testing purposes.
public RequestQueue newVolleyRequestQueueForTest(final Context context) {
    File cacheDir = new File(context.getCacheDir(), "cache/volley");
    Network network = new BasicNetwork(new HurlStack());
    ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network, 4, responseDelivery);
    queue.start();
    return queue;
}

然后,在测试期间将其用作 Volley 的请求队列。

这里的关键是:

ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());

希望这会有所帮助!

【讨论】:

  • 您能否详细说明您的答案,以便对其他人也有用?
  • @middlestump 是的,抱歉,在我用 okhttp 回复了一个相同性质的问题后,我忘记了这个答案。现在用代码更新。
  • Mockito 不喜欢这样: new MockContext().getCacheDir() 。我该怎么办?
  • @AlbertoM 您必须模拟该功能。我只是这样做:when(mockContext.getCacheDir()).thenReturn(new File("test"));
  • 我正在尝试这个解决方案,但它不适用于我的情况。我将此函数用作请求队列,但我仍然无法在单元测试中获得响应。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2019-07-19
相关资源
最近更新 更多