Android AsyncTask和Mockito(或PowreMockito)

我有一个配置管理器,可从远程服务器检索json.然后将其解析为ConfigWrapper对象,并在提供的Callback侦听器中将该对象作为参数返回.

因此,在测试课程中,我称之为:

@Test
public void init_Configuration_With_Network_Load_JSON_From_Server_Return_To_Listener() {

    mockConnectivityCheck(true);

    ...

    mManager.initConfiguration(mContext, eq(anyString()), mListener);

    verify(mListener, times(1)).onConfigurationLoaded(any(ConfigWrapper.class));

}

模拟了mContext并且模拟了mListener.
这将调用被测类的方法:

    public void initConfiguration(Context context, String url, ConfigurationManagerListener listener){
        // Get a reference to shared preferences
        mSharedPref = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);

        // If we have network, we should load configurations from remote, otherwise, try to load it from assets folder OR shared pref
        if (NetworkTools.hasNetworkConnection(context)){
            getConfigurationRemote(context, url, listener);
        } else {
            getConfigurationOffline(context, listener);
        }
    }

因此,如果我们有网络,则可以从服务器获取配置.
这个方法做到了:

private void getConfigurationRemote(final Context context, String url, final ConfigurationManagerListener
        listener) {

    // Send a request to get the configuration
    new AsyncTask<String, Void, HashMap<String, Object>> () {

        @Override
        protected HashMap<String, Object> doInBackground(String... params) {
            InputStream in = null;
            HashMap result = null;
            try {
                URL url = new URL(params[0]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setReadTimeout(10000 /* milliseconds */);
                conn.setConnectTimeout(10000 /* milliseconds */);
                conn.setRequestMethod("GET");
                conn.setDoInput(true);
                conn.connect();
                in = conn.getInputStream();
                result = new ObjectMapper().readValue(in, HashMap.class);
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (in != null){
                        in.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

                return result;
            }
        }

        @Override
        protected void onPostExecute(HashMap<String, Object> config) {

            // We if have a valid result, save the data to shared pref AND save it to a ConfigurationWrapper object
            // other wise, try to load from assets folder or shared pref if available
            if (config != null && config.size() > 0){

                // We want to save the hierarchy of the JSON so we save its string representation to shared pref
                JSONObject object = new JSONObject(config);
                mSharedPref.edit().putString(CONFIGURATIONS_KEY, object.toString()).apply();
                mConfigurationWrapper = new ConfigWrapper(config);
                listener.onConfigurationLoaded(mConfigurationWrapper);
            } else {
                // No valid configuration from remote server, so load it from local source
                getConfigurationOffline(context, listener);
            }
        }

    }.execute(url);
}

现在,我试图使用Mockito(或PowerMockito,如果需要)编写一个可以测试此代码的单元测试.
我不完全确定如何解决这种情况,在这种情况下,我将调用其中具有新的AsyncTask().execute()的方法.
到目前为止,在调用execute()之后,将停止调用initConfiguration方法并模拟网络检查以返回true. doInBackground()似乎没有被调用.

您将如何测试这样的代码?
谢谢!

解决方法:

代码的设置方式使单元测试变得困难.我建议重新安排它.

getConfigurationRemote方法当前执行3个单独的操作:

>创建AsyncTask
>定义该任务的作用
>执行任务

我的解决方案:

>将匿名AsyncTask移至其自己的类.
>将任务的创建(新的AsyncTask(….)移到工厂类,或者最好使用诸如Dagger之类的依赖项注入框架.

这就是我最终想象的样子:

private void getConfigurationRemote(final Context context, String url, final ConfigurationManagerListener listener) {
    // create the task
    ConfigurationRemoteAsyncTask task = taskFactory.createConfigurationRemoteTask(listener);
    // Send a request to get the configuration
    task.execute(url);
}

现在,您可以更轻松地进行模拟和测试:

>通过简单地模拟任务工厂返回的任务,验证在调用.initConfiguration时是否使用给定的URL调用task.execute.
>验证在调用task.onPostExecute时是否调用了listener.onConfigurationLoaded,而不模拟整个网络基础结构.可能看起来像这样:

@Test
public void init_Configuration_With_Network_Load_JSON_From_Server_Return_To_Listener() {
    ConfigurationRemoteAsyncTask task = new ConfigurationRemoteAsyncTask(mockedListener);
    HashMap<String, Object> config = getNotEmptyConfig();
    task.onPostExecute(config);
    verify(mockedListener).onConfigurationLoaded(any(ConfigWrapper.class));
}
上一篇:java-用所述类的抽象版本模拟通用类


下一篇:java-如何“拦截”测试的方法调用?