单元测试与Android凌空抽射 [英] Unit testing with Android volley

查看:131
本文介绍了单元测试与Android凌空抽射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道我怎么可以创建单元测试凌空框架。嘲笑请求,响应,这样我可以创建单元测试,不会需要一个Web服务是工作和网络accesss。

我GOOGLE了,但我没有找到有关的所有框架多的信息

解决方案

我实现的一个子类

HttpStack 的命名的装载假的响应主体从位于水库本地文件的 FakeHttpStack 的/生。我这样做是为发展宗旨,即我可以开发一些新的API服务器准备就绪之前,但你可能会学到一些东西(例如,覆盖HttpStack#peformRequest和createEntity)从这里开始。

  / **
 *假{@link HttpStack}返回使用RES /原始资源文件中的假内容。
 * /
类FakeHttpStack实现HttpStack {
    私有静态最后弦乐DEFAULT_STRING_RESPONSE =你好;
    私有静态最后弦乐DEFAULT_JSON_RESPONSE ={\一\:1,\B \:2,\C \:3};
    私有静态最后弦乐URL_ preFIX =htt​​p://example.com/;
    私有静态最后弦乐LOGGER_TAG =STACK_OVER_FLOW;

    私有静态最终诠释SIMULATED_DELAY_MS = 500;
    私人最终上下文的背景下;

    FakeHttpStack(上下文的背景下){
        this.context =背景;
    }

    @覆盖
    公众的Htt presponse performRequest(请求<>的要求,地图<字符串,字符串> stringStringMap)
            抛出IOException异常,AuthFailureError {
        尝试 {
            视频下载(SIMULATED_DELAY_MS);
        }赶上(InterruptedException异常E){
        }
        HTT presponse响应
                =新BasicHtt presponse(新BasicStatusLine(HttpVersion.HTTP_1_1,200,OK));
        名单<头>标题= defaultHeaders();
        response.setHeaders(headers.toArray(新标题[0]));
        response.setLocale(Locale.JAPAN);
        response.setEntity(createEntity(要求));
        返回响应;
    }

    私人列表<头> defaultHeaders(){
        日期格式日期格式=新的SimpleDateFormat(EEE,DD MMM YYYY HH:MM:SS ZZZ);
        返回列表<头> newArrayList(
                新BasicHeader(日期,dateFormat.format(新日期()))
                新BasicHeader(服务器,
                        / *数据下面是我的服务器*的头信息/
                        阿帕奇/ 42年3月1日(UNIX)的mod_ssl / 31年2月8日的OpenSSL / 0.9.8e)
        );
    }

    / **
     *返回使用RES /原始资源文件中的假内容。 fake_res_foo.txt用于
     *要求http://example.com/foo
     * /
    私人HttpEntity createEntity(申请要求)抛出UnsupportedEncodingException {
        字符串资源名称= constructFakeResponseFileName(要求);
        INT RESOURCEID = context.getResources()。则getIdentifier(
                资源名称,原始,context.getApplicationContext()getPackageName())。
        如果(RESOURCEID == 0){
            Log.w(LOGGER_TAG,无假冒文件命名为+资源名称
                    +,发现默认的假响应应该被使用。);
        } 其他 {
            。InputStream的流= context.getResources()openRawResource(RESOURCEID);
            尝试 {
                串串= CharStreams.toString(新InputStreamReader的(流Charsets.UTF_8));
                返回新StringEntity(串);
            }赶上(IOException异常E){
                Log.e(LOGGER_TAG,读取错误+资源名称,E);
            }
        }

        //返回默认值,因为没有假的文件存在指定的URL。
        如果(请求的instanceof StringRequest){
            返回新StringEntity(DEFAULT_STRING_RESPONSE);
        }
        返回新StringEntity(DEFAULT_JSON_RESPONSE);
    }

    / **
     *地图请求URL伪造文件名
     * /
    私人字符串constructFakeResponseFileName(申请要求){
        串reqUrl = request.getUrl();
        字符串apiName = reqUrl.substring(URL_ preFIX.length());
        回归fake_res_+ apiName;
    }
}
 

要使用FakeHttpStack,你就必须将它传递给你的请求队列的。我重写请求队列了。

 公共类FakeRequestQueue扩展请求队列{
    公共FakeRequestQueue(上下文的背景下){
        超级(新NOCACHE(),新BasicNetwork(新FakeHttpStack(上下文)));
    }
}
 

好点的这种方法是,它不需要在code太大的变化。你只需要在测试时切换您的请求队列的到的 FakeRequestQueue 的。因此,它可以在验收测试或系统测试中使用。

在另一方面,单元测试,可能有更紧凑的方式。例如,你可以实现你的 Request.Listener 的子类作为单独的类,以便onResponse方法可以很容易地进行测试。我建议你​​把更多的细节要测试或放一些code片段的东西。

I would like to know how can I create unit tests for the volley framework. Mock the requests, the responses so that I can create unit tests that wont require a webservice to be working and network accesss.

I've googled it but I don't find much information about the framework at all

解决方案

I implemented a subclass of HttpStack named FakeHttpStack that load fake response body from local file located in res/raw. I did this for development purpose, i.e., I can develop something for new API before server is ready, but you may learn something (e.g., overriding HttpStack#peformRequest and createEntity) from here.

/**
 * Fake {@link HttpStack} that returns the fake content using resource file in res/raw.
 */
class FakeHttpStack implements HttpStack {
    private static final String DEFAULT_STRING_RESPONSE = "Hello";
    private static final String DEFAULT_JSON_RESPONSE = " {\"a\":1,\"b\":2,\"c\":3}";
    private static final String URL_PREFIX = "http://example.com/";
    private static final String LOGGER_TAG = "STACK_OVER_FLOW";

    private static final int SIMULATED_DELAY_MS = 500;
    private final Context context;

    FakeHttpStack(Context context) {
        this.context = context;
    }

    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> stringStringMap)
            throws IOException, AuthFailureError {
        try {
            Thread.sleep(SIMULATED_DELAY_MS);
        } catch (InterruptedException e) {
        }
        HttpResponse response
                = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK"));
        List<Header> headers = defaultHeaders();
        response.setHeaders(headers.toArray(new Header[0]));
        response.setLocale(Locale.JAPAN);
        response.setEntity(createEntity(request));
        return response;
    }

    private List<Header> defaultHeaders() {
        DateFormat dateFormat = new SimpleDateFormat("EEE, dd mmm yyyy HH:mm:ss zzz");
        return Lists.<Header>newArrayList(
                new BasicHeader("Date", dateFormat.format(new Date())),
                new BasicHeader("Server",
                        /* Data below is header info of my server */
                        "Apache/1.3.42 (Unix) mod_ssl/2.8.31 OpenSSL/0.9.8e")
        );
    }

    /**
     * returns the fake content using resource file in res/raw. fake_res_foo.txt is used for
     * request to http://example.com/foo
     */
    private HttpEntity createEntity(Request request) throws UnsupportedEncodingException {
        String resourceName = constructFakeResponseFileName(request);
        int resourceId = context.getResources().getIdentifier(
                resourceName, "raw", context.getApplicationContext().getPackageName());
        if (resourceId == 0) {
            Log.w(LOGGER_TAG, "No fake file named " + resourceName
                    + " found. default fake response should be used.");
        } else {
            InputStream stream = context.getResources().openRawResource(resourceId);
            try {
                String string = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
                return new StringEntity(string);
            } catch (IOException e) {
                Log.e(LOGGER_TAG, "error reading " + resourceName, e);
            }
        }

        // Return default value since no fake file exists for given URL.
        if (request instanceof StringRequest) {
            return new StringEntity(DEFAULT_STRING_RESPONSE);
        }
        return new StringEntity(DEFAULT_JSON_RESPONSE);
    }

    /**
     * Map request URL to fake file name
     */
    private String constructFakeResponseFileName(Request request) {
        String reqUrl = request.getUrl();
        String apiName = reqUrl.substring(URL_PREFIX.length());
        return "fake_res_" + apiName;
    }
}

To use FakeHttpStack, you just have to pass it to your RequestQueue. I override RequestQueue too.

public class FakeRequestQueue extends RequestQueue {
    public FakeRequestQueue(Context context) {
        super(new NoCache(), new BasicNetwork(new FakeHttpStack(context)));
    }
}

Good point for this approach is that, it doesn't require much change in your code. You just have to switch your RequestQueue to FakeRequestQueue when testing. Thus, it can be used in acceptance testing or system testing.

On the other hand, for unit testing, there might be more compact way. For instance, you can implement your Request.Listener subclass as separate class so that onResponse method can be easily tested. I recommend you to put more detail about what you want to test or put some code fragment.

这篇关于单元测试与Android凌空抽射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆