简体   繁体   English

单元测试静态方法

[英]Unit Testing a static method

I am trying to write a test case for the method decrypt here. 我正在尝试为此处的方法解密编写测试用例。

    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;
    }

Test Case: 测试用例:

    @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);
    }

Since this is a static method, I can't inject an instance of the class in the test suite and mock its codec. 由于这是一个静态方法,因此我无法在测试套件中注入该类的实例并模拟其编解码器。 The above code throws an error from the codec library at assert as expected. 上面的代码按预期从assert处的编解码器库引发错误。

What is your approach to testing static methods like this? 您测试这种静态方法的方法是什么? Or should I not be writing tests for this at all? 还是我根本不应该为此编写测试?

There are many different and shortcut ways of achieving the same (as pointed out in comments and other answers), but not all of them are good in the long run especially. 有许多不同的捷径可以达到相同的目的(如评论和其他答案中指出的那样),但从长远来看,并不是所有的方法都是好的。

I would suggest creating a Singleton class which implements the Decrypt functionality. 我建议创建一个实现Decrypt功能的Singleton类。 So, you won't have to create multiple instances, and don't really need to have static method for decrypting as well, and you can inject your codec once and more easily (I assume you don't have multiple types of codec as per your comments. But, if you do, then the functionality shall be adapted accordingly). 因此,您将不必创建多个实例,也不需要真正地使用静态方法进行解密,并且可以一次又一次轻松地注入编解码器(我假设您没有多种类型的编解码器,根据您的意见。但是,如果您这样做,则功能应作相应调整)。

For more reference: Why use a singleton instead of static methods? 有关更多参考: 为什么使用单例而不是静态方法?

For reference on why static should be used carefully:- Why are static variables considered evil? 作为参考,为什么要谨慎使用static:- 为什么将static变量视为邪恶?

In Java, static methods are not designed to set dependencies. 在Java中,静态方法并非旨在设置依赖项。
So switching the dependency into a mock is really not natural. 因此,将依赖关系转换为模拟实际上是不自然的。
You could provide a static setter for the field such as : 您可以为字段提供static设置器,例如:

private static Codec codec;
public static void setCodec(Codec codec){
   this.codec = codec;
}

And you could set a mock with setCodec(...) but ugh... 你可以用setCodec(...)设置一个模拟,但是

But forget, just do things well : refactor the code to remove all static and introduce a constructor that sets the codec. 但是,算了,做得好:重构代码以删除所有静态变量,并引入一个设置编解码器的构造函数。

private Codec codec;
public MyClassUnderTest(Codec codec){
   this.codec codec;
}

IOC could help here to make the class under test a singleton and ease the dependency injections. IOC可以帮助使受测类成为单例并减轻依赖项的注入。
If not possible in your case, Java 5 enumeration could help you for at least the singleton concern. 如果无法解决,Java 5枚举至少可以帮助您解决单例问题。

In my experience in those cases I just prepare all instances in a @Before method: 根据我在这些情况下的经验,我只是使用@Before方法准备所有实例:

private Codec codec;

@Before
public void setup() throws CodecException {
  codec = new Codec(encryptionType, encryptionKey, false, true, false);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM