← Recipes

阅读中文版本

Fuzz a JSON Parser with Property Tests

Generate random and adversarial inputs to assert your JSON handling never crashes and always round-trips valid documents.

~35 mintestingfuzzingjavascript

Task

Write property-based tests asserting parse-serialise round trips and graceful failure on malformed input.

When to use this

A custom parser crashes on deeply nested or unusual input that unit tests never generate.

Prerequisites

  • A property-testing library such as fast-check
  • The parser under test
  • A defined valid-input space

Steps

1. Assert round-trip for valid values.

fc.assert(fc.property(fc.jsonValue(), (value) => {
  expect(parse(serialize(value))).toEqual(value);
}));

Expected output: Any generated valid JSON value survives a round trip unchanged.

2. Assert graceful failure on malformed input.

fc.assert(fc.property(fc.string(), (garbage) => {
  try { parse(garbage); } catch (e) { expect(e).toBeInstanceOf(SyntaxError); }
}));

Expected output: Malformed input raises a controlled error instead of crashing the process.

Troubleshooting

Problem

Shrinking produces confusing input

Solution

Use the shrunk counterexample and add it as a fixed regression case.

Problem

Generator too broad

Solution

Constrain generators to the actual input space to find meaningful bugs.

Limitations

  • Property tests explore randomly, not exhaustively.
  • Slow properties can time out CI.
  • Found counterexamples must be pinned as regressions.

What this recipe does

Write property-based tests asserting parse-serialise round trips and graceful failure on malformed input.

A custom parser crashes on deeply nested or unusual input that unit tests never generate.

Prerequisites

  • A property-testing library such as fast-check
  • The parser under test
  • A defined valid-input space

Procedure

  1. Assert round-trip for valid values.
fc.assert(fc.property(fc.jsonValue(), (value) => {
  expect(parse(serialize(value))).toEqual(value);
}));

Expected result: Any generated valid JSON value survives a round trip unchanged.

  1. Assert graceful failure on malformed input.
fc.assert(fc.property(fc.string(), (garbage) => {
  try { parse(garbage); } catch (e) { expect(e).toBeInstanceOf(SyntaxError); }
}));

Expected result: Malformed input raises a controlled error instead of crashing the process.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows fuzzing finds no crash and any counterexample is reproduced by a pinned regression test.

Troubleshooting

Shrinking produces confusing input — Use the shrunk counterexample and add it as a fixed regression case.

Generator too broad — Constrain generators to the actual input space to find meaningful bugs.

Limitations

  • Property tests explore randomly, not exhaustively.
  • Slow properties can time out CI.
  • Found counterexamples must be pinned as regressions.