assertNotEquals succeeds when two supplied values are considered unequal, but that description hides an important ambiguity: which direction of equals() is tested? Equality-contract tests can therefore pass even when equals() is badly implemented. In TestNG 7.4.0, assertNotEquals is effectively the opposite of assertEquals: it succeeds when either directional comparison is false, or when one value is null. section 10.6
A weak equality test
assertNotEquals(new MyCustomClass(), ""); class MyCustomClass { @Override public boolean equals(Object obj) { return true; } } This test can still pass because String.equals(MyCustomClass) returns false, even if MyCustomClass.equals(String) incorrectly returns true. A null argument can also avoid calling equals() entirely. section 10.6
A malformed call
assertNotEquals("Check that content was modified", storage.getContent()); When the intended call is assertNotEquals("Check that content was modified", oldContent, storage.getContent()), the two-argument form may treat the message as a value. The assertion then tests the wrong fact and may always pass unless the content equals that string. section 10.2
Avoid treating a passing negative assertion as strong evidence.
- Prefer a positive, specific assertion that establishes the expected value rather than merely ruling out one value. section 10.2
- Verify every assertion by deliberately seeing it fail; test-driven development makes this check explicit. section 10.2
- Use static analysis as supporting evidence: IntelliJ IDEA can detect some obviously non-null assertion arguments, but not every malformed or weak assertion. section 10.2
