Android单元测试(五):网络接口测试

这篇具有很好参考价值的文章主要介绍了Android单元测试(五):网络接口测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

温馨提示:如果你不太熟悉单元测试,可以先看下之前四篇基础框架使用。便于你更好的理解下面的内容。

在平日的开发中,我们用后台写好给我们接口去获取数据。虽然我们有一些请求接口的工具,可以快速的拿到返回数据。但是在一些异常情况的处理上就不太方便了。我列出以下几个痛点:

  • 快速的查看返回数据与数据的处理。(一般我们都是将写好的代码跑到手机上,点击到对应页面的对应按钮)

  • 异常信息的返回与处理。比如一个接口返回一个列表数据,如果列表为空呢?(找后台给我们模拟数据)网速不好呢?(不知道怎么搞…)网络异常呢?(关闭网络)

  • 后台有部分接口没有写好,你就只能等他了。

不知道上面的这三点有没有戳到你的痛处。如果扎心了,那么老铁你就有必要掌握今天的内容。

1.请求接口

我们就使用网络请求三件套(retrofit + okhttp + rxjava2)来举例。

首先添加一下依赖,同时记得加网络权限。

  //RxJava
    compile 'io.reactivex.rxjava2:rxjava:2.1.7'
    //RxAndroid
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    //okhttp
    compile "com.squareup.okhttp3:okhttp:3.9.1"
    //Retrofit
    compile ("com.squareup.retrofit2:retrofit:2.3.0"){
        exclude module: 'okhttp'
    }
    compile ("com.squareup.retrofit2:adapter-rxjava2:2.3.0"){
        exclude module: 'rxjava'
    }
    compile "com.squareup.retrofit2:converter-gson:2.3.0"

测试接口:

public interface GithubApi {

    String BASE_URL = "https://api.github.com/";

    @GET("users/{username}")
    Observable<User> getUser(@Path("username") String username);
}

Retrofit的初始化,我们使用LoggingInterceptor来打印返回数据。

public class GithubService {

    private static Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(GithubApi.BASE_URL)
            .client(getOkHttpClient())
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();

    public static GithubApi createGithubService() {
        return retrofit.create(GithubApi.class);
    }

    private static OkHttpClient getOkHttpClient(){
        return new OkHttpClient.Builder()
                .addInterceptor(new LoggingInterceptor())
                .build();
    }
}

测试代码:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class ResponseTest {

    @Before
    public void setUp() {
        ShadowLog.stream = System.out;
        initRxJava2();
    }

    private void initRxJava2() {
        RxJavaPlugins.reset();
        RxJavaPlugins.setIoSchedulerHandler(new Function<Scheduler, Scheduler>() {
            @Override
            public Scheduler apply(Scheduler scheduler) throws Exception {
                return Schedulers.trampoline();
            }
        });
        RxAndroidPlugins.reset();
        RxAndroidPlugins.setMainThreadSchedulerHandler(new Function<Scheduler, Scheduler>() {
            @Override
            public Scheduler apply(Scheduler scheduler) throws Exception {
                return Schedulers.trampoline();
            }
        });
    }

    @Test
    public void getUserTest() {
        GithubService.createGithubService()
                .getUser("simplezhli")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<User>() {
                    @Override
                    public void onSubscribe(Disposable d) {}

                    @Override
                    public void onNext(User user) {
                        assertEquals("唯鹿", user.name);
                        assertEquals("http://blog.csdn.net/qq_17766199", user.blog);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("Test", e.toString());
                    }

                    @Override
                    public void onComplete() {}
                });
    }
}

上面的代码中,因为网络请求是异步的,所以我们直接测试是不能直接拿到数据,因此无法打印出Log以及测试。所以我们使用initRxJava2()方法将异步转化为同步。这样我们就可以看到返回信息。测试结果如下:

Android单元测试(五):网络接口测试

上面的例子为了简单直观的说明,所以将请求接口的方法写到了测试类中,实际中我们可以Mock方法所在的类直接调用请求方法。配合Robolectric对View控件的状态进行测试。

如果你觉得每次测试都要加initRxJava2这段方法很麻烦,你可以抽象出来,或者使用@Rule

public class RxJavaRule implements TestRule {

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                RxJavaPlugins.reset();
                RxJavaPlugins.setIoSchedulerHandler(new Function<Scheduler, Scheduler>() {
                    @Override
                    public Scheduler apply(Scheduler scheduler) throws Exception {
                        return Schedulers.trampoline();
                    }
                });
                RxAndroidPlugins.reset();
                RxAndroidPlugins.setMainThreadSchedulerHandler(new Function<Scheduler, Scheduler>() {
                    @Override
                    public Scheduler apply(Scheduler scheduler) throws Exception {
                        return Schedulers.trampoline();
                    }
                });

                base.evaluate();
            }
        };
    }
}

2.模拟数据

1.使用拦截器模拟数据

利用okhttp的拦截器模拟响应数据。

public class MockInterceptor implements Interceptor {

    private final String responseString; //你要模拟返回的数据

    public MockInterceptor(String responseString) {
        this.responseString = responseString;
    }

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {

        Response response = new Response.Builder()
                .code(200)
                .message(responseString)
                .request(chain.request())
                .protocol(Protocol.HTTP_1_0)
                .body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))
                .addHeader("content-type", "application/json")
                .build();
        return response;
    }
}

测试代码:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class MockGithubServiceTest {

    private GithubApi mockGithubService;

    @Rule
    public RxJavaRule rule = new RxJavaRule();

    @Before
    public void setUp() throws URISyntaxException {

        ShadowLog.stream = System.out;

        //定义Http Client,并添加拦截器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new LoggingInterceptor())
                .addInterceptor(new MockInterceptor("json数据"))//<-- 添加拦截器
                .build();

        //设置Http Client
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GithubApi.BASE_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

        mockGithubService = retrofit.create(GithubApi.class);
    }

    @Test
    public void getUserTest() throws Exception {
        mockGithubService.getUser("weilu") //<-- 这里传入错误的用户名
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<User>() {
                    @Override
                    public void onSubscribe(Disposable d) {}

                    @Override
                    public void onNext(User user) {
                        assertEquals("唯鹿", user.name);
                        assertEquals("http://blog.csdn.net/qq_17766199", user.blog);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("Test", e.toString());
                    }

                    @Override
                    public void onComplete() {}
                });
    }

}

虽然我们传入了错误的用户名,但是我们模拟的响应信息已经提前设定好了,所以测试结果不变。

利用这个思路,我们可以修改MockInterceptor的code,模拟404的情况。

Android单元测试(五):网络接口测试

2.MockWebServer

MockWebServer是square出品的跟随okhttp一起发布,用来Mock服务器行为的库。MockWebServer能帮我们做的事情:

  • 可以设置http response的header、body、status code等。
  • 可以记录接收到的请求,获取请求的body、header、method、path、HTTP version。
  • 可以模拟网速慢的网络环境。
  • 提供Dispatcher,让mockWebServer可以根据不同的请求进行不同的反馈。

添加依赖:

testCompile 'com.squareup.okhttp3:mockwebserver:3.9.1'

测试代码:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class MockWebServerTest {

    private GithubApi mockGithubService;
    private MockWebServer server;

    @Rule
    public RxJavaRule rule = new RxJavaRule();

    @Before
    public void setUp(){
        ShadowLog.stream = System.out;

        // 创建一个 MockWebServer
        server = new MockWebServer();

        //设置响应,默认返回http code是 200
        MockResponse mockResponse = new MockResponse()
                .addHeader("Content-Type", "application/json;charset=utf-8")
                .addHeader("Cache-Control", "no-cache")
                .setBody("{\"id\": 12456431, " +
                         " \"name\": \"唯鹿\"," +
                         " \"blog\": \"http://blog.csdn.net/qq_17766199\"}");

        MockResponse mockResponse1 = new MockResponse()
                .addHeader("Content-Type", "application/json;charset=utf-8")
                .setResponseCode(404)
                .throttleBody(5, 1, TimeUnit.SECONDS) //一秒传递5个字节,模拟网速慢的情况
                .setBody("{\"error\": \"网络异常\"}");

        server.enqueue(mockResponse); //成功响应
        server.enqueue(mockResponse1);//失败响应

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new LoggingInterceptor())
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://" + server.getHostName() + ":" + server.getPort() + "/") //设置对应的Host与端口号
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

        mockGithubService = retrofit.create(GithubApi.class);

    }

    @Test
    public void getUserTest() throws Exception {
        //请求不变
        mockGithubService.getUser("simplezhli")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<User>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(User user) {
                        assertEquals("唯鹿", user.name);
                        assertEquals("http://blog.csdn.net/qq_17766199", user.blog);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("Test", e.toString());
                    }

                    @Override
                    public void onComplete() {
                    }
                });

        //验证我们的请求客户端是否按预期生成了请求
        RecordedRequest request = server.takeRequest();
        assertEquals("GET /users/simplezhli HTTP/1.1", request.getRequestLine());
        assertEquals("okhttp/3.9.1", request.getHeader("User-Agent"));

        // 关闭服务
        server.shutdown();
    }
}

代码中的注释写的很清楚了,就不用过多的解释了,使用起来非常的简单。

执行结果(成功):

Android单元测试(五):网络接口测试

失败结果:

Android单元测试(五):网络接口测试

默认情况下 MockWebServer 预置的响应是先进先出的。这样可能对你的测试有限制,这时可以通过Dispatcher来处理,比如通过请求的路径来选择转发。

    Dispatcher dispatcher = new Dispatcher() {

            @Override
            public MockResponse dispatch(RecordedRequest request) throws InterruptedException {

                if (request.getPath().equals("/users/simplezhli")){
                    return new MockResponse()
                            .addHeader("Content-Type", "application/json;charset=utf-8")
                            .addHeader("Cache-Control", "no-cache")
                            .setBody("{\"id\": 12456431, " +
                                    " \"name\": \"唯鹿\"," +
                                    " \"blog\": \"http://blog.csdn.net/qq_17766199\"}");
                } else {
                    return new MockResponse()
                            .addHeader("Content-Type", "application/json;charset=utf-8")
                            .setResponseCode(404)
                            .throttleBody(5, 1, TimeUnit.SECONDS) //一秒传递5个字节
                            .setBody("{\"error\": \"网络异常\"}");
                }
            }
        };

        server.setDispatcher(dispatcher); //设置Dispatcher

通过上面的例子,是不是可以很好的解决你的痛点,希望对你有帮助。只要我们有和后台有开发文档,约定好数据格式与字段名,那么我们可以更敏捷的去做我们的开发。文章来源地址https://www.toymoban.com/news/detail-476326.html

到了这里,关于Android单元测试(五):网络接口测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go 单元测试之mock接口测试

    目录 一、gomock 工具介绍 二、安装 三、使用 3.1 指定三个参数 3.2 使用命令为接口生成 mock 实现 3.3 使用make 命令封装处理mock 四、接口单元测试步骤 三、小黄书Service层单元测试 四、flags 五、打桩(stub) 参数 六、总结 6.1 测试用例定义 6.2 设计测试用例 6.3 执行测试用例代码

    2024年04月22日
    浏览(25)
  • 单元测试系列 | 如何更好地测试依赖外部接口的方法

    在现在这个微服务时代,我们项目中经常都会遇到很多业务逻辑是依赖其他服务或者第三方接口。工作中各位同学对于这类型场景的测试方式也是五花八门,有些是直接构建一个外部 mock 服务,返回一些固定的 response ;有些是单元测试都不写,直接利用IDE工具,通过 debug 模式

    2024年02月04日
    浏览(25)
  • JUnit5单元测试提示“Not tests were found”错误

    JUnit5单元测试提示“Not tests were found”错误,如下图所示: 或者 问题解析: 1)使用@Test注解时,不能有返回值; 2)使用@Test注解时,不能使用private; 存在以上情况时执行单元测试,都会提示“Not tests were found”错误,如下图所示: 正确的示例是使用public void定

    2024年01月16日
    浏览(40)
  • Android下单元测试实践——测试框架简介

    测试代码的写法可以归纳为三部分 第一部分: 准备测试数据和定义mock行为 第二部分: 调用真实的函数 第三部分: 调用验证函数进行结果的验证 在模块的test路径下编写测试案例。在类中使用@Test注解,就可以告诉Junit这个方法是测试方式。同时使用assert*方法,可以调用J

    2024年02月04日
    浏览(28)
  • Python接口自动化之unittest单元测试

    以下主要介绍unittest特性、运行流程及实际案例。 一、单元测试三连问 1、 什么是单元测试?   按照阶段来分,一般就是单元测试,集成测试,系统测试,验收测试。单元测试是对 单个模块 、 单个类 或者 单个函数 进行测试。 将访问接口的过程封装在函数里面; 接口测试就

    2024年02月07日
    浏览(38)
  • Android 单元测试初体验

    当初在学校学安卓的时候,老师敢教学进度,翻到单元测试这一章节的时候提了两句,没有把单元测试当重点讲,只是说我们工作中几乎不会用到,果真在之前的几年工作当中我真的没有用到,工作中都没有写过单元测试,后来我自己也下意识的忽略了这一块,直到听说现在

    2024年02月03日
    浏览(34)
  • Android 单元测试之PowerMock

    class PowerMockClassTest { @Test fun isFileExists() { // Mock 一个 File对象 val file = PowerMockito.mock(File::class.java) // 创建当前类 val powerMockitoClass = PowerMockClass() // 当Mock对象被调用了 exists() 方法,则返回False PowerMockito. when (file.exists()).thenReturn(false) // 进行断言 assertFalse(file.exists()) } } 对于这种

    2024年04月23日
    浏览(30)
  • Android 自动化单元测试

    2024年02月13日
    浏览(32)
  • Android 单元测试之 Mockk

    relaxed : 是否对其代码进行依赖,默认为否,这个参数比较关键,后续会更细的讲解一下 moreInterfaces : 让这个mock出来的对象实现这些声明的接口 relaxUnitFun :和 relaxed 差不多,但是只针对于 返回值是Unit 的方法, 后续会讲解一下 block : 该语句块表示你在创建完 mock 对象后

    2024年02月02日
    浏览(19)
  • 必备技能~Java编程使用Junit实现接口单元测试,快速实现接口全覆盖(1)

    2.Post请求方法 ========== public static String getJsonData(String urls,int command,String json) { StringBuffer sb=new StringBuffer(); try { // 创建url资源 URL url = new URL(urls); // 建立http连接 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置允许输出 conn.setDoOutput(true); // 设置允许输入 conn.setDoInput(t

    2024年04月23日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包