单测编写

单元测试的三部曲

  1. 打桩,即为非测试目标方法设置返回值,这些返回值在测试目标方法中被使用。
  2. 执行测试,调用测试目标方法。
  3. 验证测试结果,如测试方法是否被执行,测试结果是否正确等。

上报测试

  /** 被测代码 */
  fun reportLikedVideoRemoveExposure(num: String?, feed: stMetaFeed?, rank: String?, userId: String?) {
        val map = JsonObject()
        map.addProperty("num", num ?: "")
        map.addProperty("rank", rank ?: "")
        map.addProperty("user_id", userId ?: "")

        Router.getService(BeaconReportService::class.java).reportUserExposure("liked.remove", "1", map.toString(), feed?.id ?: "", feed?.poster_id ?: "")
    }


这里就使用PowerMock来写单测,mockk的步骤一样

    // 真实对象方法执行时对方法体中的对象方法进行mock和验证
    @Test
    public void testReportLikedVideoRemoveExposure() {
        BeaconReportService service = mock(BeaconReportService.class); // 使用mock后该对象的属性是null,方法没有实际执行能力

        JsonObject jsonObject = getJsonObject("1", "1", "aswq");

        mockStatic(Router.class); // reportLikedVideoRemoveExposure()方法调用了静态方法需要提前mock其行为
        when(Router.getService(BeaconReportService.class)).thenReturn(service); // 指定mock对象的方法行为
        PersonalCenterReport.INSTANCE.reportLikedVideoRemoveExposure("1", any(), "1" ,"aswq");
        verify(service)
                .reportUserExposure(Mockito.eq("liked.remove"), Mockito.eq("1"),
                        eq(jsonObject.toString()), eq(""), eq(
                                "")); // 验证结果
    }

    @NotNull
    private JsonObject getJsonObject(String num, String rank, String userId) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("num", num);
        jsonObject.addProperty("rank", rank);
        jsonObject.addProperty("user_id", userId);
        return jsonObject;
    }

    @Test
    public void testReportLikedVideoRemoveExposure_null() {
        BeaconReportService service = mock(BeaconReportService.class);

        JsonObject jsonObject = getJsonObject("1", "1", "aswq");

        mockStatic(Router.class);
        when(Router.getService(BeaconReportService.class)).thenReturn(service);
        PersonalCenterReport.INSTANCE.reportLikedVideoRemoveExposure("1", any(), "1" ,"aswq");
        verify(service)
                .reportUserExposure(Mockito.eq("liked.remove"), Mockito.eq("1"),
                        eq(jsonObject.toString()), eq(""), eq(
                                ""));
    }

使用PowerMock时需要注意:
@PrepareForTest({Router.class, BeaconReportService.class})

@Rule
public PowerMockRule rule = new PowerMockRule();

被测方法使用kotlin编写,需要把?.的两种情况都覆盖到才会有单测覆盖率

mockk时
[0]: argument: richlike.remove, matcher: eq(richlike.video), result: -
[1]: argument: 1, matcher: eq(1), result: +
[2]: argument: {"num":"1","rank":"","user_id":""}, matcher: eq({"video_cover":"big","num":"1","label":"0","search_id":"","search_word":""}), result: -
[3]: argument: , matcher: eq(), result: +
[4]: argument: , matcher: eq(), result: +

根据Matchers文档如下,在打桩阶段有一个原则,一个mock对象的方法,如果其若干个参数中,有一个是通过Matchers提供的,则该方法的所有参数都必须通过Matchers提供。而不能是有的参数通过Matchers提供,有的参数直接给出真实的具体值。

  1. If you are using argument matchers, all arguments have to be provided by matchers. E.g: (example shows verification but the same applies to stubbing):

  2. verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));

  3. //above is correct - eq() is also an argument matcher

  4. verify(mock).someMethod(anyInt(), anyString(), "third argument");

  5. //above is incorrect - exception will be thrown because third argument is given without argument matcher.

  6. Matcher methods like anyObject(), eq() do not return matchers. Internally, they record a matcher on a stack and return a dummy value (usually null).

上述文档中给出的示例,可以使用eq()方法将真实的具体值转换为Matchers提供的值或者在mock行为时参数使用具体的值。

你可能感兴趣的:(android知识点,android)