【问题标题】:Why do I get the error 'Method execute in android.os.AsyncTask not mocked'为什么我会收到错误“在 android.os.AsyncTask 中执行的方法未模拟”
【发布时间】:2017-06-07 10:46:18
【问题描述】:

我正在编写一个需要监听 UDP 广播消息的 Android 应用。

我正在尝试在侦听器类中模拟 AsyncTask,以便对其进行单元测试。

问题是我总是得到错误 java.lang.RuntimeException:在 android.os.AsyncTask 中执行的方法未模拟。

public class DiscoveryListener
{
    WorkGroupEventHandler workGroupEventHandler;

    private AsyncTask<Void, Void, Void> asyncTask;
    private boolean listener_active = false;

    public boolean GetListener_active()
    {
        return listener_active;
    }

    public DiscoveryListener(WorkGroupEventHandler eventHandler)
    {
        workGroupEventHandler = eventHandler;
    }

    public void Start()
    {
        if (listener_active == false)
        {
            listener_active = true;
            RunUdpListener();
        }
    }

    public void Stop()
    {
        listener_active = false;
        asyncTask.cancel(true);
    }

    public void RunUdpListener()
    {
        asyncTask = new AsyncTask<Void, Void, Void>()
        {

        @Override
        protected Void doInBackground(Void... params)
        {
            byte[] msg = new byte[4096];
            DatagramPacket datagramPacket = new DatagramPacket(msg, msg.length);
            MulticastSocket multicastReceiveSocket = null;

            try
            {
                multicastReceiveSocket = new MulticastSocket( 60000 );

                while (listener_active)
                {
                    if (isCancelled() == false)
                    {
                        multicastReceiveSocket.receive(datagramPacket);
                        ProcessIncommingMessage(datagramPacket.getAddress(), msg);
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                if (multicastReceiveSocket != null)
                {
                    multicastReceiveSocket.close();
                }
            }

            return null;
            }
        };

        asyncTask.execute();
    }
}


@RunWith(PowerMockRunner.class)
@PrepareForTest({android.util.Log.class, android.os.AsyncTask.class})
public class DiscoveryListenerUnitTest
{
    private WorkGroupEventHandler eventHandler = new WorkGroupEventHandler()
    {
        @Override
        public void onWorkGroupEventHandle(String IpAddress, String Workgroup, String SerialNumber)
        {
        }
    };

    private DiscoveryListener discoveryListener = new DiscoveryListener(eventHandler);
    private AsyncTask asyncTask;

    @Test
    public void discoveryListener_doesStart() throws Exception
    {
        PowerMockito.mockStatic(android.util.Log.class);

        PowerMockito.whenNew(AsyncTask.class).withNoArguments().thenReturn(asyncTask);
        asyncTask = PowerMockito.mock(AsyncTask.class);
        when(asyncTask.execute()).thenReturn(null);

        discoveryListener.Start();
        assertEquals(true, discoveryListener.GetListener_active());
    }
}

【问题讨论】:

    标签: java android unit-testing mockito powermock


    【解决方案1】:

    AsyncTask.execute 是 final 的,Mockito 无法模拟 final 类或方法。

        Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
    

    具体来说,这是因为 Java 可以在编译时解析链接,这意味着 Mockito 无法使用其生成的子类和方法覆盖来改变行为。

    您可以选择使用 Powermock,它使用一个特殊的类加载器来重写旧的行为,或者 Robolectric,它做同样的事情,但用 Android 特定的测试友好的替代实现(“影子”)替换类,包括一个用于 AsyncTask 的实现。

    【讨论】:

    • 感谢您的回复。我以为我通过调用 asyncTask = PowerMockito.mock(AsyncTask.class); 来使用 PowerMock你能举例说明我将如何使用 PowerMock 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 2012-01-30
    • 2017-01-17
    • 1970-01-01
    • 2020-11-05
    相关资源
    最近更新 更多