tanvi
tanvi

Reputation: 997

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?

Upvotes: 10

Views: 80199

Answers (3)

A_C
A_C

Reputation: 925

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. 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?

Upvotes: 2

davidxxx
davidxxx

Reputation: 131526

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.

Upvotes: 5

Juan Ramos
Juan Ramos

Reputation: 577

In my experience in those cases I just prepare all instances in a @Before method:

private Codec codec;

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

Upvotes: 1

Related Questions