Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

In Selenium, Assert (a hard assertion) and Verify (a soft assertion) both validate that an actual result matches an expected result. The difference is what happens on failure. When an Assert fails it throws an AssertionError, immediately halts the test, and skips every remaining step. A Verify (soft assert) records the failure but lets the test keep running, reporting all collected failures together at the end when assertAll() is called. Use Assert for critical checkpoints and Verify for multiple independent, non-blocking validations.
| Aspect | Assert (Hard Assertion) | Verify (Soft Assertion) |
|---|---|---|
| Behavior on failure | Throws AssertionError and stops the test | Records the failure and continues the test |
| Remaining steps | Skipped | Executed |
| Class (TestNG) | org.testng.Assert (static) | org.testng.asserts.SoftAssert (instance) |
| Reporting failures | Immediate | Deferred until assertAll() |
assertAll() needed? | No | Yes, or failures are silently ignored |
| Native "verify" keyword? | n/a | Only in Selenium IDE; TestNG uses SoftAssert |
| Best for | Login, payment, preconditions | Multiple field/UI checks on one page |
| Main risk | Over-strict; one failure blocks everything | Forgetting assertAll() hides failures |
An assertion is a validation checkpoint inside an automated test. It compares the actual state of the application, such as a page title, an element's text, or a boolean condition, against the value you expect. If they match, the test continues as a pass; if they do not, the assertion signals a failure that marks the test accordingly.
A point that trips up many beginners is that Selenium WebDriver itself has no assertion API. WebDriver only drives the browser. The pass/fail decision comes from the test framework you pair it with, most commonly TestNG or JUnit. In TestNG, assertions fall into two families: hard asserts, exposed through the static org.testng.Assert class, and soft asserts, exposed through the instance-based org.testng.asserts.SoftAssert class. The "Assert vs Verify" question is really a question about these two families.
A hard assertion uses the static methods on the org.testng.Assert class. The moment one of these methods fails, it throws an AssertionError, the current test method aborts, and any code after the failed line never executes. The test is reported as failed immediately. Hard assertions are the right choice when a failed check makes the rest of the test meaningless, for example if the page never loaded correctly.
The most frequently used hard-assert methods are assertEquals, assertNotEquals, assertTrue, assertFalse, assertNull, and assertNotNull. The example below validates a page title; if that check fails, the URL check beneath it is skipped entirely.
import org.testng.Assert;
import org.testng.annotations.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
public class HardAssertTest {
@Test
public void verifyHomePageTitle() {
WebDriver driver = /* RemoteWebDriver pointing at the cloud grid */ null;
driver.get("https://www.lambdatest.com");
String expected = "Cross Browser Testing Tools | Free Automated Testing";
// Hard assert: if this fails, the next line never runs
Assert.assertEquals(driver.getTitle(), expected, "Home page title mismatch");
// Skipped entirely if the assert above fails
Assert.assertTrue(driver.getCurrentUrl().contains("lambdatest"), "URL check failed");
driver.quit();
}
}"Verify" is the conceptual name for a non-blocking check. In a TestNG WebDriver project it is implemented with the org.testng.asserts.SoftAssert class. Each softAssert.assertX(...) call records the result but does not throw on failure, so the test keeps running through every check. Only when you call assertAll() at the end does the SoftAssert throw a single AssertionError that aggregates every failure it collected.
This is ideal when you want to validate several independent things on one page and see all the problems in a single run rather than fixing them one failure at a time.
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;
import org.openqa.selenium.WebDriver;
public class SoftAssertTest {
@Test
public void verifyCheckoutPageFields() {
WebDriver driver = /* RemoteWebDriver pointing at the cloud grid */ null;
driver.get("https://www.example.com/checkout");
SoftAssert softAssert = new SoftAssert();
// None of these stop the test on failure
softAssert.assertEquals(driver.findElement(/* heading */ null).getText(),
"Checkout", "Heading text wrong");
softAssert.assertTrue(driver.findElement(/* coupon */ null).isDisplayed(),
"Coupon field missing");
softAssert.assertNotNull(driver.findElement(/* total */ null).getText(),
"Order total missing");
// Reports ALL collected failures at once. Omit this and failures are ignored!
softAssert.assertAll();
driver.quit();
}
}The line to never forget is softAssert.assertAll(). Without it, the SoftAssert never throws, and a test full of failing checks will report green. This is the single most common soft-assert bug.
Much of the confusion around "Assert vs Verify" comes from terminology that changes between Selenium tools. In Selenium IDE, the record-and-playback browser extension, there are literal verify* commands (such as verifyText and verifyTitle) that continue on failure, sitting alongside assert* commands that stop the test. So in Selenium IDE, "verify" really is a first-class keyword.
In a Java WebDriver project there is no verify keyword at all. The continue-on-failure behaviour is provided by SoftAssert in TestNG. In JUnit there is no native soft assert either; teams replicate it using JUnit 5's assertAll(...) grouped-assertions helper, AssertJ's SoftAssertions, or simple try/catch blocks that log failures and continue. The behaviour is the same idea; only the API differs. This distinction is exactly what most comparison articles miss.
The differences between the two come down to three things:
assertAll() runs, then surfaces every collected failure in one consolidated result.org.testng.Assert class with no object to manage. Soft asserts require a fresh SoftAssert instance per test and an explicit assertAll() call to take effect.Choosing between them is mostly about whether later steps still make sense after a failure.
assertAll(): Without it, a SoftAssert never throws and a failing test reports as passed. Always close a soft-assert block with assertAll().assertAll()) never run.SoftAssert instance across tests: Sharing an instance across multiple @Test methods leaks state and produces misleading aggregate results. Create a fresh instance in each test.Hard and soft assertions behave identically whether you run them locally or on a remote grid; the assertion logic is the same. What changes across environments is everything around the assertion, the browser engine, the OS, rendering, and timing. A check that passes on your machine can fail on a different browser/OS pair, and that is exactly where cross-browser coverage matters.
With TestMu AI Selenium Automation, you point your RemoteWebDriver at the cloud and run the same TestNG suite across thousands of real browser and OS combinations in parallel. Detailed logs, video recordings, and step-level results make it far easier to triage a failed assertAll(), because you can see exactly which check failed on which browser instead of guessing from a stack trace.
No. A literal verify command only exists in Selenium IDE. Selenium WebDriver has no assertions at all. In a Java WebDriver project you implement the verify (continue-on-failure) behaviour with TestNG's SoftAssert class or a JUnit equivalent.
A hard assert (org.testng.Assert) throws an AssertionError on the first failure and stops the test, so the remaining steps are skipped. A soft assert (org.testng.asserts.SoftAssert) records each failure but lets the test continue, then reports every collected failure at once when assertAll() is called.
Yes, but only when assertAll() runs at the end. The individual softAssert.assertX() calls record failures silently, and assertAll() then throws a single error that aggregates them. If you forget to call assertAll(), the test passes even though checks failed.
Yes, and it is a common pattern. Use a hard Assert for the critical precondition that must pass, then use a SoftAssert for the follow-up, independent UI checks. Just remember that a hard assert placed mid-test will short-circuit any soft asserts that come after it.
The most common cause is a missing assertAll() call. A SoftAssert only throws when assertAll() executes, so without it the recorded failures are never raised and the test reports as passed.
No. assertEquals is just one of many methods on the org.testng.Assert class. Assert is the class that exposes hard-assertion methods such as assertEquals, assertTrue, assertFalse, assertNull, and assertNotNull.
KaneAI - Testing Assistant
World’s first AI-Native E2E testing agent.

TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance