Unit tests

Extract pure domain logic

Move validation and transformation rules into small functions whose outputs depend only on explicit inputs.

8 minute lesson

~~~

Pure logic is cheap to test because it does not need a server, database, clock, network, or cleanup.

Extract book normalization and validation from the route handler. Return a value or a typed result instead of mutating global state. Keep HTTP status selection in the HTTP layer.

export function normalizeBook(input) {
  const title = input.title?.trim() ?? ''
  const author = input.author?.trim() ?? ''
  const year = input.year === '' || input.year == null
    ? null
    : Number(input.year)

  if (!title) return { ok: false, field: 'title', reason: 'required' }
  if (!author) return { ok: false, field: 'author', reason: 'required' }
  if (year !== null && !Number.isInteger(year)) {
    return { ok: false, field: 'year', reason: 'integer' }
  }

  return { ok: true, value: { title, author, year } }
}

This function owns a domain decision: what counts as a valid book value. The HTTP handler owns a transport decision: turning a failed result into a 400 JSON response. Keeping those decisions separate prevents a unit test from needing to construct a Request, and prevents the domain function from knowing about Hono.

Purity is not a goal by itself. Do not extract a one-line wrapper merely to mock it. Extract logic when explicit inputs and outputs make an important rule easier to see. The remaining route still needs an integration test, because a perfectly tested normalizer does not prove that the handler calls it or serializes its result correctly.

Create and test a function that trims title and author, validates length, and normalizes an optional year. Include one test that proves the input object is not mutated and one HTTP test that proves a validation failure becomes the documented response.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →