An interesting gotcha in Java unittesting

Those of you who have more than a passing familiarity with Java will be aware of Java's semantics for object equality using '==': it returns true iff the two arguments are the same object. There's no operator overloading for the equals operator, even by built in classes; classes that want to do value equality tests are expected to override the built in 'equals()' method.

This leads to a common pitfall with Strings. The following compiles fine, with no warnings:

public static void isFoo(String s) {
  return s == "foo";
}

This won't work as intended, of course, because it will only return true if the passed in string is the very same object as our string literal "foo". Let's write a unittest to make sure everything works as expected:

@Test
public void testIsFoo() {
  assertTrue(Blah.isFoo("foo"));
  assertFalse(Blah.isFoo("bar"));
}

But wait! This test passes just fine! Something is very wrong here.

What's happening is that the Java compiler is interning string literals, so that multiple uses of the same string constant point to the same actual string object at runtime. This saves memory, but it's making it tough for us to test properly. You might ...