Why doesn't JUnit provide assertNotEquals methods?

JavaJunitAssert

Java Problem Overview


Does anybody know why JUnit 4 provides assertEquals(foo,bar) but not assertNotEqual(foo,bar) methods?

It provides assertNotSame (corresponding to assertSame) and assertFalse (corresponding to assertTrue), so it seems strange that they didn't bother including assertNotEqual.

By the way, I know that JUnit-addons provides the methods I'm looking for. I'm just asking out of curiosity.

Java Solutions


Solution 1 - Java

I'd suggest you use the newer assertThat() style asserts, which can easily describe all kinds of negations and automatically build a description of what you expected and what you got if the assertion fails:

assertThat(objectUnderTest, is(not(someOtherObject)));
assertThat(objectUnderTest, not(someOtherObject));
assertThat(objectUnderTest, not(equalTo(someOtherObject)));

All three options are equivalent, choose the one you find most readable.

To use the simple names of the methods (and allow this tense syntax to work), you need these imports:

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

Solution 2 - Java

There is an assertNotEquals in JUnit 4.11: https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume

import static org.junit.Assert.assertNotEquals;

Solution 3 - Java

I wonder same. The API of Assert is not very symmetric; for testing whether objects are the same, it provides assertSame and assertNotSame.

Of course, it is not too long to write:

assertFalse(foo.equals(bar));

With such an assertion, the only informative part of the output is unfortunately the name of the test method, so descriptive message should be formed separately:

String msg = "Expected <" + foo + "> to be unequal to <" + bar +">";
assertFalse(msg, foo.equals(bar));

That is of course so tedious, that it is better to roll your own assertNotEqual. Luckily in future it will maybe be part of the JUnit: JUnit issue 22

Solution 4 - Java

I'd argue that the absence of assertNotEqual is indeed an asymmetry and makes JUnit a bit less learnable. Mind that this is a neat case when adding a method would diminish the complexity of the API, at least for me: Symmetry helps ruling the bigger space. My guess is that the reason for the omission may be that there are too few people calling for the method. Yet, I remember a time when even assertFalse did not exist; hence, I have a positive expectation that the method might eventually be added, given that it is not a difficult one; even though I acknowledge that there are numerous workarounds, even elegant ones.

Solution 5 - Java

I'm coming to this party pretty late but I have found that the form:

static void assertTrue(java.lang.String message, boolean condition) 

can be made to work for most 'not equals' cases.

int status = doSomething() ; // expected to return 123
assertTrue("doSomething() returned unexpected status", status != 123 ) ;

Solution 6 - Java

I am working on JUnit in java 8 environment, using jUnit4.12

for me: compiler was not able to find the method assertNotEquals, even when I used
import org.junit.Assert;

So I changed
assertNotEquals("addb", string);
to
Assert.assertNotEquals("addb", string);

So if you are facing problem regarding assertNotEqual not recognized, then change it to Assert.assertNotEquals(,); it should solve your problem

Solution 7 - Java

The obvious reason that people wanted assertNotEquals() was to compare builtins without having to convert them to full blown objects first:

Verbose example:

....
assertThat(1, not(equalTo(Integer.valueOf(winningBidderId))));
....

vs.

assertNotEqual(1, winningBidderId);

Sadly since Eclipse doesn't include JUnit 4.11 by default you must be verbose.

Caveat I don't think the '1' needs to be wrapped in an Integer.valueOf() but since I'm newly returned from .NET don't count on my correctness.

Solution 8 - Java

It's better to use the Hamcrest for negative assertions rather than assertFalse as in the former the test report will show a diff for the assertion failure.

If you use assertFalse, you just get an assertion failure in the report. i.e. lost information on cause of the failure.

Solution 9 - Java

Usually I do this when I expect two objects to be equal:

assertTrue(obj1.equals(obj2));

and:

assertFalse(obj1.equals(obj2));

when they are expected to be unequal. I am aware that this not an answer to your question but it is the closest I can get. It could help others searching for what they can do in JUnit versions before JUnit 4.11.

Solution 10 - Java

I agree totally with the OP point of view. Assert.assertFalse(expected.equals(actual)) is not a natural way to express an inequality.
But I would argue that further than Assert.assertEquals(), Assert.assertNotEquals() works but is not user friendly to document what the test actually asserts and to understand/debug as the assertion fails.
So yes JUnit 4.11 and JUnit 5 provides Assert.assertNotEquals() (Assertions.assertNotEquals() in JUnit 5) but I really avoid using them.

As alternative, to assert the state of an object I general use a matcher API that digs into the object state easily, that document clearly the intention of the assertions and that is very user friendly to understand the cause of the assertion failure.

Here is an example.
Suppose I have an Animal class which I want to test the createWithNewNameAndAge() method, a method that creates a new Animal object by changing its name and its age but by keeping its favorite food.
Suppose I use Assert.assertNotEquals() to assert that the original and the new objects are different.
Here is the Animal class with a flawed implementation of createWithNewNameAndAge() :

public class Animal {

    private String name;
    private int age;
    private String favoriteFood;

    public Animal(String name, int age, String favoriteFood) {
        this.name = name;
        this.age = age;
        this.favoriteFood = favoriteFood;
    }

    // Flawed implementation : use this.name and this.age to create the 
    // new Animal instead of using the name and age parameters
    public Animal createWithNewNameAndAge(String name, int age) {
        return new Animal(this.name, this.age, this.favoriteFood);
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getFavoriteFood() {
        return favoriteFood;
    }

    @Override
    public String toString() {
        return "Animal [name=" + name + ", age=" + age + ", favoriteFood=" + favoriteFood + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((favoriteFood == null) ? 0 : favoriteFood.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Animal)) return false;

        Animal other = (Animal) obj;
        return age == other.age && favoriteFood.equals(other.favoriteFood) &&
                name.equals(other.name);
    }

}

JUnit 4.11+ (or JUnit 5) both as test runner and assertion tool

@Test
void assertListNotEquals_JUnit_way() {
    Animal scoubi = new Animal("scoubi", 10, "hay");
    Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
    Assert.assertNotEquals(scoubi, littleScoubi);
}

The test fails as expected but the cause provided to the developer is really not helpful. It just says that the values should be different and output the toString() result invoked on the actual Animal parameter :

> java.lang.AssertionError: Values should be different. Actual: Animal > > [name=scoubi, age=10, favoriteFood=hay] > > at org.junit.Assert.fail(Assert.java:88)

Ok the objects are not equals. But where is the problem ?
Which field is not correctly valued in the tested method ? One ? Two ? All of them ?
To discover it you have to dig in the createWithNewNameAndAge() implementation/use a debugger while the testing API would be much more friendly if it would make for us the differential between which is expected and which is gotten.


JUnit 4.11 as test runner and a test Matcher API as assertion tool

Here the same scenario of test but that uses AssertJ (an excellent test matcher API) to make the assertion of the Animal state: :

import org.assertj.core.api.Assertions;

@Test
void assertListNotEquals_AssertJ() {
    Animal scoubi = new Animal("scoubi", 10, "hay");
    Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
    Assertions.assertThat(littleScoubi)
              .extracting(Animal::getName, Animal::getAge, Animal::getFavoriteFood)
              .containsExactly("little scoubi", 1, "hay");
}

Of course the test still fails but this time the reason is clearly stated :

> java.lang.AssertionError: > > Expecting: > > <["scoubi", 10, "hay"]> > > to contain exactly (and in same order): > > <["little scoubi", 1, "hay"]> > > but some elements were not found: > > <["little scoubi", 1]> > > and others were not expected: > > <["scoubi", 10]> > > at junit5.MyTest.assertListNotEquals_AssertJ(MyTest.java:26)

We can read that for Animal::getName, Animal::getAge, Animal::getFavoriteFood values of the returned Animal, we expect to have these value :

"little scoubi", 1, "hay" 

but we have had these values :

"scoubi", 10, "hay"

So we know where investigate : name and age are not correctly valued. Additionally, the fact of specifying the hay value in the assertion of Animal::getFavoriteFood() allows also to more finely assert the returned Animal. We want that the objects be not the same for some properties but not necessarily for every properties.
So definitely, using a matcher API is much more clear and flexible.

Solution 11 - Java

Modulo API consistency, why JUnit didn't provide assertNotEquals() is the same reason why JUnit never provided methods like

  • assertStringMatchesTheRegex(regex, str) vs. assertStringDoesntMatchTheRegex(regex, str)
  • assertStringBeginsWith(prefix, str) vs. assertStringDoesntBeginWith(prefix, str)

i.e. there's no end to providing a specific assertion methods for the kinds of things you might want in your assertion logic!

Far better to provide composable test primitives like equalTo(...), is(...), not(...), regex(...) and let the programmer piece those together instead for more readability and sanity.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChris BView Question on Stackoverflow
Solution 1 - JavaJoachim SauerView Answer on Stackoverflow
Solution 2 - JavaStefan BirknerView Answer on Stackoverflow
Solution 3 - JavaMikko MaunuView Answer on Stackoverflow
Solution 4 - JavaBernhard BodenstorferView Answer on Stackoverflow
Solution 5 - Javauser903724View Answer on Stackoverflow
Solution 6 - JavaAkshay Vijay JainView Answer on Stackoverflow
Solution 7 - JavaMark LevisonView Answer on Stackoverflow
Solution 8 - JavaChris KellyView Answer on Stackoverflow
Solution 9 - JavaWillempieView Answer on Stackoverflow
Solution 10 - JavadavidxxxView Answer on Stackoverflow
Solution 11 - JavafatuhokuView Answer on Stackoverflow