---
title: "Empty Test"
type: "test-smell"
slug: "empty-test"
url: "http://localhost:3000/en/test-smells/empty-test.md"
category: "Dispensable Smells"
description: "An Empty Test is a test method with a body that contains no executable statements, so it always passes while verifying nothing."
---
# Empty Test

> An Empty Test is a test method with a body that contains no executable statements, so it always passes while verifying nothing.

## Signs and Symptoms

A test exists and is reported as **passing**, but its body has no executable code — no setup, no exercise, no assertion. Telltale forms:

```js
// Completely empty body
test('calculates tax', () => {});

// Only a TODO / placeholder comment
it('should reject invalid input', () => {
  // TODO: write this once the API stabilises
});

// Everything is commented out
it('parses the auth header', () => {
  // const result = parse(header);
  // expect(result).toEqual(expected);
});

```

How to spot it:

* The test name promises behaviour, but the body is `{}`, whitespace, or comments only.
* Your runner's summary shows the test as **passed** (green), not skipped/pending — this is what makes it dangerous.
* Code coverage for the named feature is suspiciously zero even though a "test for it" exists.
* During review, the diff adds a test case but no `expect`/`assert` call.

Related but distinct: a test that has setup and calls the system under test yet makes **no assertion** is the _Assertion-less / Unknown Test_ smell. An Empty Test is the more extreme case where the body is entirely devoid of statements.

## Reasons for the Problem

**Why it happens**

* A test was scaffolded as a placeholder (TDD "write the name first") and never filled in.
* Code was commented out to debug a failure or quiet a flaky test, then committed and forgotten.
* A generator/IDE produced a skeleton test stub that nobody completed.
* A developer wanted to "reserve" a test name for later but used an empty body instead of an explicit todo marker.

**Why it hurts**

* **False confidence (the worst part).** Most runners report an empty test as _passing_, not skipped. JUnit, Jest, Vitest, and friends will all show green for `test('x', () => {})`. The suite looks like it covers the behaviour, but a regression in the production code will never be caught — arguably worse than having no test at all, because the green check actively misleads.
* **Readability.** A reader sees a test named `should reject invalid input` and reasonably assumes that behaviour is verified. The name documents intent that the body never delivers.
* **Maintainability.** Empty tests inflate the test count and coverage-by-name perception, hiding genuine gaps and making it hard to tell intentional placeholders from abandoned ones.
* **Erodes trust.** Once contributors learn that "passing" doesn't mean "verified," the whole suite's signal weakens.

## Treatment

Decide whether the test should _exist yet_, then make the runner tell the truth.

**1\. If the behaviour should be tested now — fill in the body.** Add arrange/act/assert so it actually exercises the code:

```js
// Before — green, but verifies nothing
test('rounds half up', () => {});

// After — real expectation
test('rounds half up', () => {
  expect(round(2.5)).toBe(3);
});

```

**2\. If it is a genuine placeholder — mark it explicitly pending** so the runner reports it as todo/skipped (visible, not falsely green) instead of leaving an empty body:

```js
// Before
it('should reject invalid input', () => {
  // TODO
});

// After — shows up as a todo in the report, never as "passed"
it.todo('should reject invalid input');   // Jest / Vitest
// or test.skip(...) / xit(...) with a tracking ticket

```

**3\. If the test is obsolete — delete it.** A removed test is honest; an empty one is a lie that costs maintenance.

**4\. Restore commented-out logic.** If the body is fully commented out, either uncomment and fix it or remove the test; never ship commented-out test code as the "implementation."

**5\. Add a guard.** Enable an assertion-presence lint rule (see detectors) in CI so empty/assertion-less tests fail the build rather than passing silently.

## Detected by

- **eslint-jest** `expect-expect` — eslint-plugin-jest: expect-expect (flags tests with no assertion, including empty bodies) (https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/expect-expect.md)
- **eslint-vitest** `expect-expect` — eslint-plugin-vitest: expect-expect (enforces at least one expectation per test) (https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/expect-expect.md)
- **eslint** `no-empty-function` — ESLint core: no-empty-function (general rule; flags the empty arrow/function body of an empty test callback) (https://eslint.org/docs/latest/rules/no-empty-function)
- **sonar** `S2699` — SonarSource: S2699 "Tests should include assertions" (Blocker; flags assertion-less and empty tests; equivalents exist for Java/C#/Python) (https://rules.sonarsource.com/javascript/RSPEC-2699/)
- **pmd** `JUnitTestsShouldIncludeAssert` — PMD (Java): JUnitTestsShouldIncludeAssert (flags JUnit tests lacking an assertion, including empty tests) (https://pmd.github.io/pmd/pmd_rules_java_bestpractices.html#junittestsshouldincludeassert)
