Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

What is your approach to testing static methods like this? Or should I not be writing tests for this at all?

like image 931
tanvi Avatar asked Dec 10 '18 10:12

tanvi


People also ask

How do you write a unit test for static methods?

Note that you should add the class that contains static methods in two places in your unit tests: On top of the unit test class using @PrepareForTest annotation. In your test setup by calling the PowerMockito. mockStatic to do the necessary initialization step before trying to mock any of its methods.

Can I mock static class in unit test?

If you need to truly mock static methods, you need to use a commercial tool like Microsoft Fakes (part of Visual Studio Enterprise) or Typemock Isolator. Or, you can simply create a new class to wrap the static method calls, which itself can be mocked.


Video Answer


1 Answers

In Java, static methods are not designed to set dependencies.
So switching the dependency into a mock is really not natural.
You could provide a static setter for the field such as :

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

And you could set a mock with setCodec(...) but ugh...

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.
If not possible in your case, Java 5 enumeration could help you for at least the singleton concern.

like image 191
davidxxx Avatar answered Oct 06 '22 00:10

davidxxx