Home > OS >  Right way to unit test helper methods
Right way to unit test helper methods

Time:01-21

I have the following class

public class Multiplier {
    private static Map<Integer, Float> map;
    private static final float DEFAULT_MULTIPLIER = 4.4F;

    static {
        // This map is actually populated by reading from a file. This is an example on how the map looks like.
        map = new HashMap<>();
        map.put(1, "3.5F");
        map.put(2, "5.8F");
        map.put(3, "2.7F");
    }

    public static float getMultiplier(Integer id) {
        return map.getOrDefault(id, DEFAULT_MULTIPLIER);
    }
}

I want to test the getMultiplier method. What's the best way to go about it?

1st - There are 1000s of entries inside the map. Should I just call the getMultiplier method with a couple of different ids and make sure the value returned matches? The file is static. It will occasionally change in the future, but that would mean updating the test, which is fine.

2nd - I want to test the default value as well. Should I just do something like

Assert.assertEquals(4.4F, Multiplier.getMultiplier(<invalidId/null>));

I'm hardcoding the DEFAULT_MULTIPLIER value in the expected parameter of assertEquals. Does this even make sense?

I want to know what's the right way to unit test this method? Thanks!

CodePudding user response:

You shouldn't be testing any of that - it's got way too much of a "Grading your own exam" vibe. The likely errors here involve you messing up either the constant, or the static file, which a test is not likely to catch. You'll be setting yourself up for a bunch of future updates (where you update the default and then later go: Oh, right, of course, I repeated myself in the test and I forgot to update the value there). You're not testing anything - you're giving your future self pointless homework.

Get creative - what could plausibly fail in the future? Not much - this is rather simple code. Test the likely failure avenues.

If I were you, I'd test the following situations:

  • I would check that the value for a key I'm sure is never going to be in the map (not now, and not likely ever in the future) returns non-0. This avoids having to hardcode the 4.4F, or having to mark as package-private the constant value, but still ensures 2 unlikely but plausible avenues of future failure: That the .getMultiplier method throws an exception due to a bug in the future, or that it returns 0 instead of an actual value. It would avoid having to update the test if you change this default later. Unless you change it to 0 or to 'if you ask for the multiplier for a number not listed, the method now throws', which are fundamental changes to functionality and therefore should indeed cause tests to fail.

  • I would not test any value from the static file, because either you're again just testing that you correctly copied and pasted a value from it into your test source file and giving yourself future homework to update the tests when you update the file - or you're marking your own exam if you dynamically adjust the k/v pair you test by also getting it from the file (whatever bug might exist in the code that reads in this static file, it'll be in the test code too). Instead, I would take the thing that is capable of reading in the static file and turning it into that static 'map of constants' and test that. In the test code I can then have a tiny example 'input static file' and I would then test if the Multiplier class responds correctly given this known input. This frees you from future updates (the test code always supplies test static data to the code, it doesn't look at the thing that may be updated in the future and is therefore essentially 'unstable'), and lets you test the thing that could plausibly break here - the part that turns the static file into a filled map.

Once tests ensure that the 'turn static file into static map' code works, and I have tested that the getMultiplier method doesn't fail in the 2 obvious ways (throws, or, returns 0), then you've tested everything relevant.

  • Related