447

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.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Chris B
  • 9,149
  • 4
  • 32
  • 38
  • At least since JUnit 4.12, assertNotEquals is provided. https://junit.org/junit4/javadoc/4.12/org/junit/Assert.html#assertNotEquals(double,%20double,%20double) – WebF0x Oct 25 '18 at 19:29
  • Newer versions of Junit provide this functionality. here is a nice example on [how to use `assertEquals` and `assertNotEquals`](https://www.codingeek.com/tutorials/junit/a-complete-guide-to-junit-with-java-and-gradle/#6_assertions) – Hitesh Garg Apr 12 '21 at 18:16

11 Answers11

413

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.*;
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • 142
    I appreciate the pointer to the alternate assertion syntax, but pointing elsewhere doesn't answer *why* JUnit never provided `assertNotEquals()`. – seh May 31 '10 at 14:30
  • 14
    @seh: The way I read it the question was not about historical interest, but about a way to formulate the assertion "these two objects are not equal" in a JUnit test. I answered that. Considering the "why is/was there no `assertNotEqual`" I'd say that's because it's a specialized assert that's not needed as often as `assertEquals` and therefore would be expressed via the generic `assertFalse`. – Joachim Sauer May 31 '10 at 14:34
  • 21
    "choose the one you find most readable". People reading and writing unit tests are programmers. Do they really find this more readable than assertNotEqual(objectUnderTest, someOtherObject) or assertFalse(objectUnderTest.equals(someOtherObject))? I'm not convinced by the fancy matcher APIs - it seems to be considerably harder for a programmer to explore/discover how to use them... – bacar May 08 '12 at 17:49
  • @bacar: for some asserts it's basically a matter of style. But `assertThat` is a whole lot more expressive than the limited set of `assert*` methods available. Therefore you can express the exact constraints in a single line, have it (almost) read like an english sentence *and* get a meaningful message when the assert fails. Granted, that's not always a killer feature, but when you've seen it in action a few times, you'll see how much value it adds. – Joachim Sauer May 09 '12 at 05:31
  • 5
    @Joachim I agree that `assertThat` is more expressive than `assert*`, but I don't think it's more expressive than the java expression you can put inside and out of the `assert*` expression in general (after all I can express anything in java code). It's a general problem I've started coming across with fluent-style APIs - every one is basically a new DSL you have to learn (when we all already know the Java one!). I suppose Hamcrest is ubiquitous enough now that it's reasonable to expect people to know it, though. I'll have a play... – bacar May 09 '12 at 15:32
  • These are the specific imports if you don't like * imports: `import static org.junit.Assert.assertThat;` `import static org.hamcrest.CoreMatchers.is;` `import static org.hamcrest.CoreMatchers.not;` – fIwJlxSzApHEZIl Jul 29 '13 at 23:22
  • it's terrifying that this API was designed that way so that we can achieve same result in a slightly different way – shabunc Nov 16 '22 at 14:36
166

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;
Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72
  • 1
    Mind, one of the jmock (2.6.0) maven artefacts leaks an old version of junit-dep which in turn has an Assert-class without the assertNotEquals. Better exclude that when using ivy. – gkephorus Oct 01 '14 at 08:47
  • 9
    I am using 4.12 but still not able to find assertNotEqual. :s – Mubashar May 05 '15 at 05:17
52

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

k1eran
  • 4,492
  • 8
  • 50
  • 73
Mikko Maunu
  • 41,366
  • 10
  • 132
  • 135
14

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.

7

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 ) ;
user903724
  • 2,956
  • 4
  • 24
  • 27
  • 5
    While this does work, the problem is that if the assertion fails, it will simply say "Exepcted true, but was false", or some other unclear statement. What would be great is if it was Expected Not 123, but was 123. – Stealth Rabbi Jun 03 '14 at 13:21
6

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

Akshay Vijay Jain
  • 13,461
  • 8
  • 60
  • 73
  • 2
    That's because the methods are static, and you must import them statically. Use this `import static org.junit.Assert.*;` and you will be able to use all asserts without the class name. – Tom Stone Oct 05 '16 at 13:54
3

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.

Mark Levison
  • 788
  • 3
  • 9
  • 22
2

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.

2

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.

Willempie
  • 103
  • 1
  • 5
0

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.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
-1

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.

fatuhoku
  • 4,815
  • 3
  • 30
  • 70
  • 3
    well, for some reason, assertEquals() exists. It didn't have to, but it does. The question was about the lack of symmetry - why does assertEquals exist but not its counterpart? – foo Feb 11 '14 at 12:31