Explain the difference between assertSame and assertEquals, and give a case where each is correct.
answer
- assertEquals = == (structural)
- assertSame = === (reference identity)
- assertNotSame is the inverse
- use assertSame for cache/pool/singleton
- don't assertSame value types (interning)
basics
~10 sassertEquals checks two values are equal by content (==). assertSame checks they are the exact same object in memory (===). Use assertEquals for value comparison, assertSame to confirm something returned the very same instance.
solid answer
~30 s`assertEquals` uses structural equality (`==` → `.equals()`): two distinct objects with equal content pass. `assertSame` uses referential identity (`===`): only the same heap instance passes; `assertNotSame` is its inverse. Use `assertEquals` for normal value checks (data classes, strings, collections). Use `assertSame` when identity is the contract — a cache or object pool returning the same instance, a singleton, an interned object, or a fluent API returning `this`. A pitfall: small `Int`s and string literals may be interned, so `assertSame` can pass deceptively for value types; never use it to compare values. Both share the optional trailing `message` argument.
code
kotlin · 7 linesimport kotlin.test.*
val a = listOf(1, 2)
val b = listOf(1, 2)
assertEquals(a, b) // PASS: same content
assertNotSame(a, b) // PASS: different instances
assertSame(a, a) // PASS: identical referencego deeper
Knows assertEquals compares content; vaguely aware assertSame is about identity.
Clearly distinguishes == vs === and names a correct use case for each.
Warns about interning pitfalls and reserves assertSame for genuine identity contracts (cache/pool/singleton/this).
Discusses how identity assertions encode invariants in API contracts and the risk of brittle tests when identity isn't actually guaranteed.
## `assertSame` vs `assertEquals` - `assertEquals(expected, actual)` checks **structural** equality with `==` (calls `.equals()`). - `assertSame(expected, actual)` checks **referential** identity with `===` — both references must point to the *same object instance* on the heap. - `assertNotSame(illegal, actual)` is the inverse: fails if they are the same instance. ```kotlin import kotlin.test.assertSame import kotlin.test.assertEquals import kotlin.test.assertNotSame val a = listOf(1, 2) val b = listOf(1, 2) assertEquals(a, b) // PASS: structurally equal assertNotSame(a, b) // PASS: different instances // assertSame(a, b) // FAIL: not the same reference val shared = a assertSame(a, shared) // PASS: same instance ``` ### When to reach for `assertSame` - Verifying a cache / object pool returns the **same** instance. - Verifying a singleton or interned object identity. - Asserting a function returns `this` for fluent chaining. ### Gotcha: identity of boxed primitives / interned values Small `Int` values and string literals may be interned, so `assertSame` can pass "by accident" for cached values and fail for larger ones. Don't use `assertSame` to compare value types — use `assertEquals`. Reserve `assertSame` strictly for genuine reference-identity intent.
- Why can assertSame(1, 1) pass but assertSame(1000, 1000) be fragile?The JVM caches small boxed Integers (typically -128..127), so identity may hold for small values and not larger ones — exactly why you shouldn't use assertSame on value types.
- Give a real test where assertSame is the right tool.Asserting a memoizing cache returns the same object on a second call: `assertSame(cache.get(k), cache.get(k))`.
assertEquals: two twins look identical. assertSame: it's literally the same person in two photos.
saying these in an interview costs you the question
- Says assertSame and assertEquals are interchangeable
- Thinks assertSame compares content
- Uses assertSame to compare Ints/Strings as a habit
- Confuses === and == directions
- Cannot give an identity use case