Unit testing of encrypt/decrypt

12,147

A few notes on how to test this ( personal opinion warning :-) )

  • If you're writing unit tests, avoid reading expected results from files, since it slows down the test (unit tests have to be super fast), as well as create another thing irrelevant to your code that might go wrong (i.e. the file might be deleted, etc.)
  • Don't use the same method you're testing to created the expected results with which you check the method. This is pointless if you're trying to check the algorithm, and might perpetuate bugs in the algorithm
  • Consider the fact that the smallest unit of work in Java is a class, not a method (forget for a second about Java 8's lambda expressions, you won't really write unit tests for those directly), therefore, you should attempt to test the class, not the methods

My last point there brings me (finally ?) to a recommendation. Think about what's the responsibility of the class (hopefully, the single responsibility, see SRP). In this case, I believe that the responsibility of your class is two way encryption of strings.
Therefore, I would write the following tests:

@Test
public void testThatEncryptingStringResultsInExpectedBytes() {
    byte[] encryption = enigma.encryptString(TEST_STRING);

    assertArrayEquals(EXPECTED_ENCRYPTION, encryption);
}

@Test
public void testThatDecryptinEncryptionResultsInOriginalString() {
    String decryption = enigma.decryptBytes(TEST_ENCRYPTION);

    assertEquals(EXPECTED_ORIGINAL_STRING, decryption);
}

@Test
public void testThatDecriptionReversesEncryption() {
    String decryption = enigma.decryptBytes(enigma.encryptString(TEST_STRING));

    assertEquals(TEST_STRING, decryption);
}

@Test
public void testThatEncryptionReversesDecryption() {
    byte[] encryption = enigma.encriptString(enigma.decryptBytes(TEST_ENCRYPTION));

    assertEquals(TEST_ENCRYPTION, encryption);
}

Maybe add some more tests to check that trying to encrypt/decrypt invalid values throws exceptions, and other error cases.

Share:
12,147
user2891462
Author by

user2891462

Updated on June 12, 2022

Comments

  • user2891462
    user2891462 almost 2 years

    I have implemented a very simple class called Enigma which has a symmetric key and two methods: byte[] encryptString(String strToEncrypt) and String decryptBytes(byte[] arrayToDecrypt).

    I am trying to write some tests for the methods. I have thought of testing that the encrypt and decrypt methods are the inverse of each other, but that says nothing about each of them individually. I wanted to use the methods as they are now to obtain a battery of input-outputs and set that as the tests (I know that is not ideal, but the purpose of these tests is to guarantee that the function behaves in the future as it does today, not that the encryption/decryption are good).

    However, I do not know how to obtain a representation of the byte array output by byte[] encryptString(String strToEncrypt) so that I can hardcode it in the test class.

    Any ideas?

  • user2891462
    user2891462 almost 10 years
    Thank you, that is what I finally did (using an online encryption tool to get the results in hexadecimal).
  • Ewoks
    Ewoks almost 8 years
    comment and question: not sure reverses tests can be applied to every encryption (guess it makes sense just for symmetric algorithms). I agree that reading files slows down unit tests which should be lightning fast.. How you would go around it when testing xml generation with JUnit? any tips or examples on this?
  • ethanfar
    ethanfar almost 8 years
    First of all, let me just emphasize that the bigger problem than slowness (albeit a BIG problem) with reading files during unit testing, is inconsistency, loss of repeatability and loss of isolation. Reading files depends on I/O, which means that it might fail, it might take a different amount of time each run, etc. Doing I/O operations during a test inhibit it from being a unit test. Regarding XML generation, define your generator to receive the output writer/stream as a parameter to the constructor/method or by injection. The unit test will provide a mock output buffer.
  • ethanfar
    ethanfar almost 8 years
    Sorry for the short answer, there's a limit to the number of characters in a comment. If you need a better answer, please post a question and I'll reply to it properly.
  • Amir Pashazadeh
    Amir Pashazadeh over 6 years
    I encounter the same problem, but the problem is my encryptor uses a random salt, so the encrypted value can not be expected.
  • ethanfar
    ethanfar over 6 years
    The question is how do you get the random salt ? If you're instantiating an object at some point, you'll have a problem testing it. However, if you inject it (either by dependency injection or as a parameter to a constructor or method), you'll have no problem passing any mock salt that you want in the test.