Skip to main content
SeleniumDecoded

Soft Assertions: Check Several Things, Report All Failures

Verify multiple fields on one page and report every mismatch at once instead of stopping at the first.

Stable Verified against Selenium 4.48.0

Problem

A confirmation page shows order number, total, delivery date and address. With hard assertions, a wrong total hides whether the address was also wrong; you fix one, rerun, and find the next. Each cycle costs a full browser test.

Solution

Collect assertion results and fail once at the end with every discrepancy listed.

Soft assertions per language
Selenium 3 & 4 Stable
// AssertJ SoftAssertions (org.assertj:assertj-core)
import org.assertj.core.api.SoftAssertions;
SoftAssertions softly = new SoftAssertions();
softly.assertThat(page.orderNumber()).as("order number").matches("INV-\\d{4}");
softly.assertThat(page.total()).as("total").isEqualTo("$1,240.00");
softly.assertThat(page.deliveryDate()).as("delivery date").isEqualTo("15 Oct 2026");
softly.assertThat(page.address()).as("address").contains("221B Baker Street");
softly.assertAll(); // throws once, listing every failed assertion
// TestNG has org.testng.asserts.SoftAssert with the same shape; JUnit 5 has assertAll(...)
# pip install pytest-check
import pytest_check as check
def test_confirmation(driver):
page = ConfirmationPage(driver)
check.is_true(re.fullmatch(r"INV-\d{4}", page.order_number()), "order number")
check.equal(page.total(), "$1,240.00", "total")
check.equal(page.delivery_date(), "15 Oct 2026", "delivery date")
check.is_in("221B Baker Street", page.address(), "address")
# pytest-check reports all failures at the end of the test
// Collect failures manually; assertion libraries rarely ship soft mode
const failures = [];
const soft = (label, fn) => { try { fn(); } catch (e) { failures.push(`${label}: ${e.message}`); } };
soft('order number', () => assert.match(orderNumber, /^INV-\d{4}$/));
soft('total', () => assert.strictEqual(total, '$1,240.00'));
soft('delivery date', () => assert.strictEqual(deliveryDate, '15 Oct 2026'));
soft('address', () => assert.ok(address.includes('221B Baker Street')));
assert.deepStrictEqual(failures, [], `Confirmation page mismatches:\n${failures.join('\n')}`);
// NUnit: Assert.Multiple collects all failures in the block
Assert.Multiple(() =>
{
Assert.That(page.OrderNumber(), Does.Match(@"INV-\d{4}"), "order number");
Assert.That(page.Total(), Is.EqualTo("$1,240.00"), "total");
Assert.That(page.DeliveryDate(), Is.EqualTo("15 Oct 2026"), "delivery date");
Assert.That(page.Address(), Does.Contain("221B Baker Street"), "address");
});
// FluentAssertions: using (new AssertionScope()) { ... }

Why It Works

Each check records rather than throws; the final call throws a single exception whose message lists all failures. One browser run reports the full state of the page.

Gotchas

  • Use soft assertions for verification steps, not for flow steps. If the order number is missing, the page is wrong and later checks are noise; assert that hard first.
  • Always call the final assertAll (or use a scope); forgetting it silently passes the test. AssertJ’s AutoCloseableSoftAssertions in a try-with-resources avoids that.
  • Label every assertion; a report of expected "$1,240.00" but was "$1,140.00" without a label wastes the benefit.

Learn the theory