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.