24

Can someone tell me why assertSame() do fail when I use values > 127?

        import static org.junit.Assert.*;

        ...

        @Test
        public void StationTest1() {
          ..

          assertSame(4, 4);         // OK
          assertSame(10, 10);       // OK
          assertSame(100, 100);     // OK
          assertSame(127, 127);     // OK
          assertSame(128, 128);           // raises an junit.framework.AssertionFailedError!
          assertSame(((int) 128),((int) 128)); // also junit.framework.AssertionFailedError!
        }

I'm using JUnit 4.8.1.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Michael W.
  • 531
  • 2
  • 7
  • 17
  • 3
    You should use `assertSame` only for reference equality checks - for example `a == b`. For equality, you should use `assertEquals`. – Cem Catikkas May 21 '10 at 21:49

2 Answers2

47

The reason is the autoboxing of Java. You use the method:

public static void assertSame(Object expected, Object actual)

It only works with Objects. When you pass ints to this method, Java automatically calls

Integer.valueOf( int i )

with these values. So the cast to int has no effect.

For values less than 128 Java has a cache, so assertSame() compares the Integer object with itself. For values greater than 127 Java creates new instances, so assertSame() compares an Integer object with another. Because they are not the same instance, the assertSame() method returns false.

You should use the method:

public static void assertEquals(Object expected, Object actual)

instead. This method uses the equals() method from Object.

xav
  • 5,452
  • 7
  • 48
  • 57
Daniel Engmann
  • 2,840
  • 1
  • 23
  • 17
  • You are correct that the JVM *must* cache -128..127, but for values outside that range, that is entirely up to the JVM implementation what range it caches, _"Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K."_ http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7 via https://stackoverflow.com/questions/20897020/why-integer-class-caching-values-in-the-range-128-to-127/20948389#20948389 – weston Oct 08 '17 at 01:14
12

assertSame takes two Object arguments, and so the compiler has to autobox your int literals into Integer.

This is equivalent to

assertSame(Integer.valueOf(128), Integer.valueOf(128));

Now for values between -128 and 127, the JVM will cache the results of Integer.valueOf, so you get the same Integer object back each time. For values outside of that range, you get new objects back.

So for assertSame(127, 127), JUnit is comparing the same objects, hence it works. For assertSame(128, 128), you get different objects, so it fails.

Just another reason to be careful with autoboxing.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • You are correct that the JVM must cache -128..127, but for values outside that range, that is entirely up to the JVM implementation what range it caches, _"Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K."_ http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7 via https://stackoverflow.com/a/20948389/360211 – weston Oct 08 '17 at 10:52