Assertions and Soft Assertions
An assertion is the mechanism by which a Selenium test actually verifies application behavior against an expected value — everything before the assertion (navigating, clicking, typing) just drives the browser, but it's the Assert call that turns a script into a real test with a pass/fail verdict. A 'hard' assertion (TestNG's org.testng.Assert or JUnit's org.junit.jupiter.api.Assertions) immediately throws an exception and halts that test method the instant the check fails, which is correct behavior when a later step genuinely depends on the earlier condition being true, such as needing to be logged in before checking a dashboard widget.
Cricket analogy: The umpire's raised finger is the actual verdict on an lbw appeal — everything before that (the bowler's approach, the delivery) just sets up the situation, but the decision is what makes it count; a hard assertion is that same decisive, halting verdict in a test.
Hard Assertions with TestNG and JUnit
TestNG's Assert class offers static methods like assertEquals(actual, expected), assertTrue(condition), assertFalse(condition), and assertNotNull(object), each accepting an optional message string that appears in the report on failure — always pass a descriptive message, since 'expected [true] but found [false]' alone gives almost no debugging context weeks later. JUnit 5's Assertions class mirrors this (assertEquals, assertTrue, assertThrows for exception testing), with the notable ergonomic difference that JUnit 5 places the message as the last parameter (assertEquals(expected, actual, message)) while TestNG traditionally places it last as well in modern versions but historically varied — a detail worth double-checking against the exact library version in use.
Cricket analogy: A scorecard entry that just says 'out' without recording how (bowled, caught, run out) is nearly useless for later analysis; an assertion without a descriptive message is that same uninformative record, whereas 'c Smith b Bumrah for 12' is the equivalent of a good assertion message.
// Hard assertion (TestNG) — stops immediately on failure
Assert.assertEquals(
dashboardPage.getWelcomeText(),
"Welcome, qa_user",
"Welcome banner text did not match after login"
);
// JUnit 5 equivalent
Assertions.assertEquals("Welcome, qa_user",
dashboardPage.getWelcomeText(),
"Welcome banner text did not match after login");
// --- Soft assertion (TestNG) — collects failures, keeps executing ---
SoftAssert softAssert = new SoftAssert();
softAssert.assertEquals(profilePage.getFullName(), "Jane Doe", "Full name mismatch");
softAssert.assertEquals(profilePage.getEmail(), "jane@example.com", "Email mismatch");
softAssert.assertTrue(profilePage.isAvatarDisplayed(), "Avatar not displayed");
softAssert.assertAll(); // MUST be called, or failures are silently swallowed
Soft Assertions in TestNG
TestNG's SoftAssert class inverts the halt-on-failure behavior: calling softAssert.assertEquals(...), assertTrue(...), etc. records any failure internally but lets execution continue to the next line, which is exactly what you want when validating multiple independent fields on one page — a profile page's name, email, and avatar are unrelated checks, and you want to know about all three failures in one run rather than fixing one, re-running, and discovering the next failure. The collected failures only surface when softAssert.assertAll() is explicitly called at the end of the test method; forgetting that call is a classic bug that makes a test report as passed even though every soft assertion inside it actually failed.
Cricket analogy: A post-innings review checks every dismissal on the scorecard at once (each batsman's mode of dismissal) rather than stopping analysis at the first wicket; SoftAssert collects every failed check the same way and reports them all together via assertAll().
Forgetting to call softAssert.assertAll() at the end of a test method is a well-known and dangerous mistake: every individual soft assertion inside that method can fail, but because assertAll() never ran to surface those collected failures, TestNG reports the entire test as PASSED. Always place assertAll() as the very last line of the test method, and consider a base test class or @AfterMethod hook that calls it automatically to eliminate the risk of forgetting.
AssertJ and Custom Soft Assertions
Beyond TestNG's built-in SoftAssert, the AssertJ library provides a more expressive, fluent alternative via assertThat(actual).isEqualTo(expected) syntax and its own org.assertj.core.api.SoftAssertions class, which works the same collect-then-report way but reads more naturally for chained multi-field checks (softAssertions.assertThat(user.getName()).as("name").isEqualTo("Jane")) and integrates with both TestNG and JUnit since it isn't tied to either framework's assertion mechanism. For teams validating complex objects returned from a page (like a full order confirmation with multiple line items), AssertJ's assertThat(order).usingRecursiveComparison().isEqualTo(expectedOrder) can replace dozens of individual field-by-field assertions with a single readable, deep-comparison call.
Cricket analogy: Modern ball-tracking systems like Hawk-Eye give a single, richly detailed readout (trajectory, impact point, pitching point) instead of a bare 'out/not out'; AssertJ's fluent, descriptive assertions give that same richer readout compared to a bare boolean check.
- An assertion is what turns a Selenium script into a real test by checking actual state against an expected value.
- Hard assertions (TestNG Assert, JUnit Assertions) throw immediately on failure, halting the rest of that test method.
- Always pass a descriptive message to assertions so failures are diagnosable without re-running the test.
- TestNG's SoftAssert collects multiple failures without halting execution, ideal for validating several independent fields on one page.
- softAssert.assertAll() must be called explicitly at the end of the test method, or collected failures are silently swallowed and the test reports as passed.
- AssertJ provides a fluent assertThat(...) syntax and its own SoftAssertions class usable with either TestNG or JUnit.
- AssertJ's usingRecursiveComparison() can replace many individual field assertions with a single deep-comparison call for complex objects.
Practice what you learned
1. What happens immediately when a hard assertion like Assert.assertEquals fails in a test method?
2. What is the critical requirement for TestNG's SoftAssert failures to actually be reported?
3. In what scenario is a soft assertion more appropriate than a hard assertion?
4. What does AssertJ's usingRecursiveComparison() primarily help accomplish?
5. Why should assertion calls include a descriptive message parameter?
Was this page helpful?
You May Also Like
Selenium with TestNG
Learn how TestNG's annotations, grouping, and reporting turn raw Selenium WebDriver scripts into a structured, parallelizable, CI-ready test suite.
Selenium with JUnit
Learn how JUnit 5's lifecycle annotations, extension model, and tagging integrate with Selenium WebDriver to build maintainable Java test suites.
Data-Driven Testing
Learn how to separate test logic from input data in Selenium frameworks using TestNG's @DataProvider and JUnit 5's @ParameterizedTest.