0

I am trying to unit test a function that takes a HashMap and concatenates the keys into a comma separated string. The problem is that when I iterate through the HashMap using entrySet (or keySet or valueSet) the values are not in the order I .put() them in. IE:

testData = new HashMap<String, String>(0);
testData.put("colA", "valA");
testData.put("colB", "valB");
testData.put("colC", "valC");
for (Map.Entry<String, String> entry : testData.entrySet()) {
    System.out.println("TestMapping " + entry.getKey());
}

Gives me the following output:

TestMapping colB
TestMapping colC
TestMapping colA

The string created by the SUT is ColB,ColC,ColA

How can I unit test this, since keySet(), valueSet(), etc are somewhat arbitrary in their order?

This is the function I am trying to test:

public String getColumns() {
    String str = "";
    for (String key : data.keySet()) {
        str += ", " + key;
    }
    return str.substring(1);
}
Holger
  • 285,553
  • 42
  • 434
  • 765
Wige
  • 3,788
  • 8
  • 37
  • 58
  • 3
    Why would they be?! `LinkedHashMap` maintains intention order, the `Map` `interface` does not define an iteration order. – Boris the Spider Jan 03 '17 at 19:22
  • 1
    `HashMap` does not guarantee insertion order upon traversal. You need to use something like `LinkedHashMap` instead. – M A Jan 03 '17 at 19:23
  • 1
    What problem are you trying to solve? You mentioned you can't use arrays, so you decided to go with `HashMap` - this is a very strange criteria to choose data structure. If you need resizable array you can use `ArrayList`. – Igor Nikolaev Jan 03 '17 at 19:28
  • I am trying to unit test a function that concatenates the keys of a HashMap into a string. Since I can't predict the order of the values going into the function from my unit test, I am unable to predict the string that will be created. I edited the question to hopefully better address this, and hopefully not be a duplicate. – Wige Jan 03 '17 at 21:18

2 Answers2

2

There is no point in iterating over the HashMap in this case. The only reason to iterate over it would be to construct the expected String, in other words, perform the same operation as the method under test, so if you made an error implementing the method, you are likely to repeat the error when implementing the same for the unit test, failing to spot the error.

You should focus on the validity of the output. One way to test it, is to split it into the keys and check whether they match the keys of the source map:

testData = new HashMap<>();
testData.put("colA", "valA");
testData.put("colB", "valB");
testData.put("colC", "valC");

String result = getColumn();
assertEquals(testData.keySet(), new HashSet<>(Arrays.asList(result.split(", "))));

You are in control of the test data, so you can ensure that no ", " appears within the key strings.

Note that in its current form, your question’s method would fail, because the result String has an additional leading space. You have to decide whether it is intentional (in this case, you have to change the test to assertEquals(testData.keySet(), new HashSet<>(Arrays.asList(result.substring(1) .split(", "))));) or a spotted bug (then, you have to change the method’s last line to return str.substring(2);).

Don’t forget to make a testcase for an empty map…

Holger
  • 285,553
  • 42
  • 434
  • 765
1

HashMap does not maintain insertion order....If you want insertion order to be maintained use a linkedhashmap

prashant
  • 1,382
  • 1
  • 13
  • 19
  • Please search for duplicates before answering. If you choose to answer, please write a decent answer; preferably with references - not just a single sentence that should be a comment. – Boris the Spider Jan 03 '17 at 19:26
  • When you say with references.....in this case should I have given a reference to the java docs – prashant Jan 03 '17 at 19:28
  • Ideally you should reference your claim that ’HashMap’ has an undefined iteration order, and also your claim that `LinkedHashMap` has a defined iteration order. If you're really pulling out the stops, then you could post the OP's code snippet with it rewritten to use a `LinkedHashMap`; but I don't think that is necessarily required in this case, just a nice-to-have. – Boris the Spider Jan 03 '17 at 19:31