skip to content

Fixture and Body Nodes

Setup and teardown against the body of a check: Allure holds fixtures outside the result, in a container naming its children, while ReportPortal makes them item types in the same tree.

on this pageshow

explore

questions

5

In an Allure results directory, what does a `-container.json` file hold, and how does it relate to the `-result.json` files beside it?

level: juniorimportance: must knowfreq 62%

answer

  1. two file suffixes, not one
  2. fixtures live beside the case
  3. befores and afters
  4. children is a list of uuids
  5. FixtureResult has no uuid

basics

~10 s

A -container.json file holds Allure's TestResultContainer: setup in befores, teardown in afters, and a children list naming by uuid the results it wraps. The test bodies themselves live in separate -result.json files.

solid answer

~40 s

Allure's writer emits loose JSON into a results directory. A `-result.json` file is one finished test case — a `TestResult` with its own `steps`, `attachments` and `status`. A `-container.json` file is a **scope**: a `TestResultContainer` whose `befores` and `afters` hold `FixtureResult` objects for setup and teardown, and whose `children` is a list of **uuids** — not embedded objects — naming the results (or nested containers) that scope covers. So a fixture is never stored inside the test it prepared; it is stored once, beside it, and the container is what says which cases it applied to. That is why a results directory of `-result.json` files alone still renders test bodies, but shows no setup or teardown at all.

code

json · 34 lines
json
{
  "uuid": "6b1f0f1e-6c02-4b4a-a0e6-2b3b3f0f9a11",
  "name": "CheckoutTest",
  "children": [
    "7c2a1b33-1d0f-4d55-9c2e-0f7c5c1a7c10",
    "9d4e77aa-58cb-4c1a-8f21-5a6f0c2e44b3"
  ],
  "befores": [
    {
      "name": "startSession",
      "status": "passed",
      "stage": "finished",
      "steps": [],
      "attachments": [],
      "parameters": [],
      "start": 1717070000000,
      "stop": 1717070001200
    }
  ],
  "afters": [
    {
      "name": "closeSession",
      "status": "passed",
      "stage": "finished",
      "steps": [],
      "attachments": [],
      "parameters": [],
      "start": 1717070009000,
      "stop": 1717070009400
    }
  ],
  "start": 1717070000000,
  "stop": 1717070009400
}

go deeper

for a junior

Be able to name the two file suffixes and say what each holds: the case body in a result file, the setup and teardown in a container file that lists its children by uuid.

for a middle

Explain the field-level mechanics: befores and afters hold FixtureResult objects with the same shape as StepResult, and children is a list of uuid strings rather than embedded objects.

for a senior

Show you can debug from the raw directory — grep a case uuid to find every container that covered it, and recognise a partial run where results flushed but the enclosing container never closed.

for a principal

Be ready to argue why fixtures were kept out of the result file at all: shared scopes, nesting, and independently written files that stay readable when a run is cut short.

## What the writer puts in a results directory Allure's writer side (`allure-java`) does not build a report. It drops **loose JSON files** into a results directory — `allure-results` by default, overridable through the `allure.results.directory` property — and a separate generator step reads them afterwards. Three file suffixes matter for the step tree: - **`-result.json`** — one finished test case, serialised from `TestResult`. - **`-container.json`** — one *scope*, serialised from `TestResultContainer`. - **`-attachment`** plus the file's own extension — raw bytes referenced by name from a node. Every file is named by a uuid, so nothing in the directory depends on write order and parallel workers can emit into it independently. ## The container: two fixture lists and a list of children `TestResultContainer` carries `uuid`, `name`, `children`, `description`, `descriptionHtml`, `befores`, `afters`, `links`, `start` and `stop`. Two of those fields do the real work: - **`befores`** and **`afters`** are lists of `FixtureResult` — the setup that ran on entry to the scope and the teardown that ran on exit. The writer distinguishes the two directions with a fixture type whose values are `BEFORE` and `AFTER`. - **`children`** is a list of **strings**, not of objects. Each string is the uuid of something else in the same directory: a `-result.json` file, or another `-container.json` file. That second point is the whole design. A container does not contain its children; it **names** them. Containers can therefore nest — a class-scoped container's `children` may list method-scoped containers, which in turn list results. | | `-result.json` (`TestResult`) | `-container.json` (`TestResultContainer`) | |---|---|---| | what it is | one executed test case | one scope around zero or more cases | | body | `steps`, `attachments`, `parameters` | none of its own | | fixtures | none | `befores`, `afters` | | identity | `uuid`, `historyId`, `testCaseId`, `labels`, `links` | `uuid` and `name` only | | membership | implicit, via labels | explicit, via `children` uuids | ## What a `FixtureResult` is — and what it is not A `FixtureResult` has `name`, `status`, `statusDetails`, `stage`, `description`, `descriptionHtml`, `steps`, `attachments`, `parameters`, `start` and `stop`. That is the **same field set as `StepResult`**: both are executable items, so a fixture can carry its own nested steps and its own attachments, exactly as a test body can. Its `status` is one of `FAILED`, `BROKEN`, `PASSED`, `SKIPPED`; its `stage` is one of `SCHEDULED`, `RUNNING`, `FINISHED`, `PENDING`, `INTERRUPTED`. What it does **not** have is just as important: - no `uuid` of its own, - no `historyId` and no `testCaseId`, - no `labels`. A fixture has no independent identity in this model. It exists only as an element of some container's `befores` or `afters`, and it is reachable only through that container. Nothing in the format lets you trend one fixture across runs the way you can trend a case. ## Why the split exists 1. **A fixture is shared.** One class-scoped setup serves many cases. Storing it once and naming the covered cases by uuid avoids writing the same object into every result file. 2. **Scopes nest.** Suite, class and method scopes stack, and a flat list of results has nowhere to put that stacking. `children` gives it a place. 3. **The files are written at different moments.** A result is written when the case finishes; a container is written when its scope closes — after the children it names. The directory is therefore correct at every intermediate point, which is what lets a killed run still produce a readable partial report. ## Reading a results directory by hand When a report looks wrong, the directory is the ground truth: - **Bodies but no setup shown?** Look for `-container.json` files. If the run was killed before the outer scope closed, the results were flushed and the container never was. - **Which fixture applied to this case?** Take the case's `uuid` from its `-result.json` and grep the directory for it; every container whose `children` list contains it contributed its `befores` and `afters`. - **A fixture that seems to have run many times?** Check whether it is one entry in one container that names many children, rather than many entries. The short version: the result file answers *what the test did*; the container file answers *what was done around it, and to whom*.

  • Can one `-container.json` name another `-container.json` in its `children`?
    Yes. `children` is a list of uuid strings and nothing constrains them to results, so a class-scoped container can name method-scoped containers, which in turn name the results. That is how nested scopes are represented in a flat directory of files.
  • If a fixture has no `uuid` of its own, how would you follow one fixture across several runs?
    You cannot do it through the format. A `FixtureResult` carries only `name`, timing, `status` and its own steps and attachments — no identity key, no labels. Any cross-run view of a fixture has to be reconstructed outside the report, by matching on the container name and the fixture name.

Think of a shipping manifest. The boxes (the -result.json files) travel as separate parcels; the manifest (the -container.json) lists the box IDs in this shipment and records the paperwork done before dispatch and after arrival.

saying these in an interview costs you the question

  • Says fixtures are stored inside the test result file
  • Thinks children embeds the full child results
  • Calls a container just another test case
  • Assumes one container file per test method always
  • Believes a fixture has its own historyId
open as a page

Allure stores fixtures in a container rather than in the test result, so how does the generated report end up showing setup and teardown on an individual test case's page?

level: middleimportance: must knowfreq 55%

basics

~20 s

The reader joins on uuid. Every container's befores and afters are folded onto each child uuid it names, so the report's test result gains beforeStages, testStage and afterStages built from those fixtures plus the case's own steps.

open as a page

ReportPortal reports a setup method as a `BEFORE_METHOD` test item inside the same tree as the steps — so what does the `awareStatistics` flag on `TestItemTypeEnum` decide about that node?

level: middleimportance: should knowfreq 46%

basics

~20 s

awareStatistics decides whether an item counts toward a launch's totals. Every BEFORE and AFTER type in TestItemTypeEnum has it false, so a fixture node shows its status and logs but never inflates pass or fail counts.

open as a page

In an Allure report, one failed class-level setup shows up as the same failure on ten different test case pages. How does the container model produce that, and what must you not conclude from it?

level: seniorimportance: should knowfreq 44%

basics

~20 s

One container holds the failed fixture once in its befores and names ten children, so the reader attributes the same FixtureResult to each of them. Do not read it as ten setup runs, ten failures, or ten times the duration.

open as a page

Two result models place setup and teardown differently: one holds fixtures in a separate container that names its children, the other makes them typed items inside the same tree. What does each shape cost a tool that consolidates results?

level: principalimportance: nice to knowfreq 34%

basics

~20 s

A sidecar container stores a shared fixture once but gives it no identity and a join that can silently resolve to nothing. Typed in-tree items give a fixture an id and logs, but every consumer must exclude them from counts.

open as a page