Assertions Complete

ID

csharp.assertions_complete

Severity

critical

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

CSharp

Tags

assertion, reliability, testing

Description

Reports a comparison assertion whose expected and actual arguments are the same expression, so the comparison is decided before the code under test is ever consulted: Assert.Equal(x, x), Assert.AreEqual(cart.Total, cart.Total), Assert.NotEqual(name, name).

The comparison is structural — the two arguments span the same sequence of parsed tokens, so comments and formatting are ignored. It is deliberately not applied when either side contains a call, because two invocations that read alike need not return the same value and asserting that a call is stable across two evaluations is a legitimate test.

The equality, identity and set-equivalence families of xUnit, NUnit and MSTest are covered.

This rule applies to test code only.

Rationale

An assertion is a statement about two independent things: the value the test expects and the value the code produced. When both sides are the same expression, one of the two is missing. The equality forms then hold by construction and the test passes without touching the behaviour it names; the inequality forms fail by construction and are only ever an unfinished edit.

The usual causes are a copy of the expected side over the actual one, and an assertion whose second argument was never filled in after the test was generated or duplicated from a neighbour.

[Fact]
public void TotalMatchesExpected()
{
    var expected = 12;
    Assert.Equal(expected, expected);                     // FLAW - the actual value is missing
}

[Fact]
public void CartTotalIsStable()
{
    var cart = new Cart();
    Assert.AreEqual(cart.Total, cart.Total);              // FLAW - compares a value with itself
}

[Fact]
public void TotalMatchesActual()
{
    var expected = 12;
    var cart = new Cart();
    Assert.Equal(expected, cart.Total);                   // OK
}

[Fact]
public void TotalIsRepeatable()
{
    var cart = new Cart();
    Assert.Equal(cart.Recalculate(), cart.Recalculate()); // OK - calls need not return the same value
}

[Fact]
public void ItemsDiffer()
{
    var items = new List<string> { "a", "b" };
    Assert.NotEqual(items[0], items[1]);                  // OK - different elements
}

Remediation

Put the value produced by the code under test on the actual side, and the value the test expects on the other. If the intent was to check that an operation is idempotent or that a value is stable across two reads, write the two evaluations explicitly instead of repeating one expression, so the assertion says what it means.