mockito,如何模拟作为容器类成员的类

问题描述

使用 mockito-inline 如何测试静态函数(使用 stubbing 其他静态函数),或 mock/stub 一些内部依赖类?

示例如下:

一个 class Util,它内部依赖于 java.security.MessageDigest

package java.security;
public abstract class MessageDigest extends MessageDigestSpi
    ... ...
    public byte[] digest() {
       
        byte[] result = engineDigest();       
        return result;
    }
}

并且容器类有一些静态函数需要测试

public class Util {

    public static byte[] getStringDigest(@NonNull String text,@NonNull String algorithm,@NonNull String charSet) {
        if (text == null) {
            return null;
        }
        MessageDigest messageDigest;  //<== depend on 
        try {
            messageDigest = MessageDigest.getInstance(algorithm);
            messageDigest.update(text.getBytes(charSet));
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
            return null;
        }

        return messageDigest.digest();
    }

    public static String generateId(@NonNull String s) {
        byte[] sha1Byte = getStringDigest(s,"SHA-1","UTF-8");
        if (sha1Byte == null) {
            return s;
        }
        // otherwise build the id
        String id = buildId(sha1Byte);
        return id;
    }
}

想要测试 Utils.generateId(@NonNull String s) 与存根 getStringDigest() 返回 null,以便一些文本预期返回。

因为它是静态函数,所以它是用 powermock 测试的。

@Test
public test_util_1{
        powermockito.mockStatic(MessageDigest.class);
        String sometext = "sometext";
        powermockito.when(Util.getStringDigest(sometext,"UTF-8")).thenReturn(null);
        assertEquals(sometext,Util.generateId(sometext));

}

使用模拟存根,当调用 Util.getStringDigest() 时返回 null效果很好。

现在mockito-inline 支持测试静态函数(并且在测试kotlin 等时与powermockito2 混合有问题)所以powermock 被删除

尝试使用 mockito-inline 3.8.0

    @Test
    public void test_util_1() {

        String sometext = "sometext";
        try (MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)) {
            utilMoc.when(() -> Util.getStringDigest(sometext,"UTF-8"))
                    .thenReturn(null);

            assertEquals(sometext,Util.generateId(sometext));

        }

出现错误

java.lang.AssertionError: Unexpected value 
Expected :sometext
Actual   :null

Util.generateId(sometext) 返回 null(不是 sometext)。

当使用 assertEquals(sometext,sutilMoc.generateId(sometext)); 时,它无法编译并说无法解析 generateId()

如何使用mockito-inline测试静态函数

或者是否有办法模拟/存根依赖的 abstract class MessageDigest 存根 digest() 以返回 null,但不知道这可能吗?

解决方法

找到了使测试工作的方法(使用 .thenCallRealMethod()),

但仍然没有找到一种方法来模拟在静态函数内实例化的依赖类。如果有人知道解决方案吗?

    @Test
    public void test_util_1() {

        String sometext = "sometext";
        try (MockedStatic<Util> utilMoc = Mockito.mockStatic(Util.class)) {
            utilMoc.when(() -> Util.getStringDigest(anyString(),anyString(),anyString()))
                    .thenReturn(null);

            // need to tell mock to call the original,otherwise a default mocked stub will be called
            utilMoc.when(() -> Util.generateId(anyString()))
                    .thenCallRealMethod();

            assertEquals(sometext,Util.generateId(sometext));

        }