skip to content

What is special about assertNotNull's return value compared with assertTrue(x != null)?

level: middleimportance: must knowfreq 65%

answer

  1. assertNotNull RETURNS the non-null value
  2. contract enables smart-cast
  3. no !! / ?. needed after
  4. assertTrue(x!=null) only checks, no narrowing
  5. assertNull is the mirror

basics

~20 s

assertNotNull both checks the value isn't null and gives you back the value as a non-null type. After it, you can use the value without ?. or !!. assertTrue(x != null) only checks; it doesn't unwrap the type.

solid answer

~40 s

`assertNotNull(actual, message?)` is declared `fun <T : Any> assertNotNull(actual: T?, message: String? = null): T` — it returns the value as the **non-null** type `T`, and a `contract` lets the original variable smart-cast. So after `val s = assertNotNull(maybe)` (or even just `assertNotNull(maybe)`), the compiler treats it as non-null and you can call members directly without `!!` or `?.`. `assertTrue(x != null)` only checks a boolean — it neither narrows the type nor unwraps, and produces a worse message (`expected true`). The mirror function `assertNull` fails unless the value is `null`. Preferring `assertNotNull` makes the rest of the test type-safe and self-documenting.

code

kotlin · 8 lines
kotlin
import kotlin.test.assertNotNull

val name: String? = repo.findName(id)
val nn: String = assertNotNull(name)  // returns non-null
println(nn.length)                    // safe

assertNotNull(name)
println(name.length)                  // smart-cast, no ?.

go deeper

for a junior

Knows assertNotNull fails on null and assertNull fails on non-null.

for a middle

Explains that assertNotNull returns the unwrapped non-null value and enables smart-cast, avoiding !!.

for a senior

Names the contract/generic signature <T:Any>(T?): T and contrasts message quality vs assertTrue.

for a principal

Advocates assertNotNull as a readability/type-safety convention and discusses how contracts propagate through the test for safer dereferencing.

## Null assertions and smart-cast benefit - `assertNull(actual, message?)` fails unless `actual` is `null`. - `assertNotNull(actual, message?)` fails unless `actual` is non-null. ### The key behavior: `assertNotNull` returns the unwrapped value `assertNotNull` is declared to **return** the value as a non-null type. Its signature is roughly `fun <T : Any> assertNotNull(actual: T?, message: String? = null): T`. After the call the compiler knows the value is non-null — either by using the returned value, or via a `contract` so the original variable smart-casts. ```kotlin import kotlin.test.assertNotNull import kotlin.test.assertNull val name: String? = repo.findName(id) // Option A: use the returned non-null value val nonNull: String = assertNotNull(name) println(nonNull.length) // no ?. needed // Option B: contract lets the original var smart-cast assertNotNull(name) println(name.length) // 'name' is now String, not String? assertNull(repo.findName(missingId)) ``` This is why `assertNotNull` is preferred over `assertTrue(x != null)`: it both asserts *and* narrows the type so the rest of the test can dereference safely without `!!` or `?.`.

  • How does the original variable become non-null without reassigning it?
    assertNotNull declares a Kotlin `contract` (returnsNotNull / implies non-null), so the compiler smart-casts the variable in the following code.
  • What's the downside of assertTrue(x != null)?
    It doesn't narrow the type (you still need !!/?.) and the failure message is just 'expected true' instead of naming the null value.

saying these in an interview costs you the question

  • Says assertNotNull returns Unit/Boolean
  • Uses !! after assertNotNull instead of the returned value
  • Claims assertTrue(x != null) smart-casts
  • Confuses assertNull and assertNotNull
  • Thinks you must reassign to get a non-null var

context