单元测试静态方法

tan*_*nvi 7 java testing static unit-testing mockito

我正在尝试为这里的方法解密编写测试用例。

    private static Codec codec;

    static {
        try {
            codec = new Codec(encryptionType, encryptionKey, false, true, false);
        } catch (CodecException e) {
            throw new RuntimeException("Codec initialisation failed", e);
        }
    }


    public static String decrypt(final String toDecrypt) throws CodecException {
        String decrypted = codec.decryptFromBase64(toDecrypt);
        if (decrypted.endsWith(":")) {
            decrypted = decrypted.substring(0, decrypted.length() - 1);
        }
        return decrypted;
    }
Run Code Online (Sandbox Code Playgroud)

测试用例:

    @Mock
    private Codec codec;
    @Test
    public void test_decrypt_Success() throws CodecException {
        when(codec.decryptFromBase64(TestConstants.toDecrypt)).thenReturn(TestConstants.decrypted);
        assertEquals(DocumentUtils.decrypt(TestConstants.toDecrypt), TestConstants.decrypted);
    }
Run Code Online (Sandbox Code Playgroud)

由于这是一个静态方法,我无法在测试套件中注入类的实例并模拟其编解码器。上面的代码按预期在 assert 处从编解码器库中抛出错误。

您测试此类静态方法的方法是什么?或者我根本不应该为此编写测试?

dav*_*xxx 5

在Java中,静态方法并不是为了设置依赖关系而设计的。
因此将依赖项切换为模拟确实不自然。
您可以为该字段提供一个static设置器,例如:

private static Codec codec;
public static void setCodec(Codec codec){
   this.codec = codec;
}
Run Code Online (Sandbox Code Playgroud)

你可以设置一个模拟,setCodec(...)但是呃......

但请忘记,只要把事情做好:重构代码以删除所有静态并引入一个设置编解码器的构造函数。

private Codec codec;
public MyClassUnderTest(Codec codec){
   this.codec codec;
}
Run Code Online (Sandbox Code Playgroud)

IOC 可以帮助使被测试的类成为单例并简化依赖注入。
如果您的情况不可能,Java 5 枚举至少可以帮助您解决单例问题。

  • 我同意单一初始化,但不同意静态使用。在 Java 中,静态方法很容易编写,并且简化了 util 方法的客户端使用。但它也有一些限制:这对依赖项进行了硬编码,因此使其无法自然切换。我通常只为不需要模拟任何东西的方法编写静态方法。关于你的问题,setter是一种方式。PowerMock 是另一种。但在你的情况下我会避免这两种情况,因为你是 api/组件开发人员。 (2认同)