3

I want to test code that produces byte arrays used to send as UDP packets.

Although I'm not able to reproduce every byte in my test (e.g. random bytes, timestamps), I'd like to test the bytes that I can predetermine.

Is something like the following possible using JUnit 4.8 (and Mockito 1.8)?

Packet packet = new RandomPacket();

byte[] bytes = new byte[] {
    0x00, 0x02, 0x05, 0x00, anyByte(), anyByte(), anyByte(), anyByte(), 0x00
};

assertArrayEquals(packet.getBytes(), bytes);

The sample above is of course not working, I'm just searching for a way to use some sort of wildcard in assertArrayEquals().

PS: My only alternative right now is to check each byte individually (and omit random ones). But this is quiet tedious and not really reusable.


Thanks to the answer from JB Nizet I have the following code in place now, working just fine:

private static int any() {
    return -1;
}

private static void assertArrayEquals(int[] expected, byte[] actual) {
    if(actual.length != expected.length) {
        fail(String.format("Arrays differ in size: expected <%d> but was <%d>", expected.length, actual.length));
    }

    for(int i = 0; i < expected.length; i ++) {
        if(expected[i] == -1) {
            continue;
        }

        if((byte) expected[i] != actual[i]) {
            fail(String.format("Arrays differ at element %d: expected <%d> but was <%d>", i, expected[i], actual[i]));
        }
    }
}
Koraktor
  • 41,357
  • 10
  • 69
  • 99

2 Answers2

2

You could simply write your expected array as an array of integers, and use a special value (such as -1) to represent the wildcard. It's the same trick as the read methods of the input streams. You would just have to write your custom assertEqualsWithWildCard(int[] expected, byte[] actual).

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • A simple, yet readable solution. Why didn't I think about that? I added the code to my question. – Koraktor Oct 25 '11 at 08:12
  • 1
    Maybe using a `Byte[]` would be more appropriate? Wildcards would then be `null`. That would be one of the few cases where a `Byte[]` was actually useful ;-) – Joachim Sauer Oct 25 '11 at 08:18
  • @Joachim : using ints also has the advantage of being able to write byte literals easily : 0xBC vs. (byte) 0xBC – JB Nizet Oct 25 '11 at 08:33
  • @JB: I see, in that case the code in the answer is not correct, 'though. Because it's missing the cast to `byte` in the line `if(expected[i] != actual[i])`: It should be `if ((byte) expected[i] != actual[i])`. – Joachim Sauer Oct 25 '11 at 08:37
  • Yes indeed. And the order of the arguments should be inversed, because the JUnit convention is to have the expected value as first argument, and the actual one as the second. – JB Nizet Oct 25 '11 at 08:43
  • Sure thing, I updated my code above. I thought of the argument order in `assertThat` that follows a different style. – Koraktor Oct 27 '11 at 07:46
1

If you are going to be writing a lot of code like this, I would write a separate class to "decode" the packet into meaningful fields. Then (of course, after testing that the class itself works) you can write sensible tests like

assertEquals(42, packet.length());
assertEquals(0xDEADBEEF, packet.checksum());

etc.

That way, you are not "omitting random bytes", and your code will be much more readable (if a tad more verbose).

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100