Почему JUnit не предоставляет методы assertNotEquals?

кто-нибудь знает, почему JUnit 4 предоставляет assertEquals(foo,bar) а не assertNotEqual(foo,bar) методами?

обеспечивает assertNotSame (соответствует assertSame) и assertFalse (соответствует assertTrue), поэтому кажется странным, что они не потрудились включить assertNotEqual.

кстати, я знаю, что JUnit-addons предоставляет методы, которые я ищу. Я спрашиваю из любопытства.

10 ответов


Я бы предложил вам использовать более новый assertThat() стиль утверждает, что может легко описать все виды отрицаний и автоматически построить описание того, что вы ожидали и что вы получили, если утверждение не удается:

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

все три варианта эквивалентны, выберите тот, который вы считаете наиболее читаемым.

чтобы использовать простые имена методов (и разрешить этот синтаксис времени для работы), вам нужны следующие импорта:

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

есть assertNotEquals в 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;

Я бы сказал, что отсутствие assertNotEqual действительно является асимметрией и делает JUnit немного менее изучаемым. Имейте в виду, что это аккуратный случай, когда добавление метода уменьшит сложность API, по крайней мере для меня: симметрия помогает управлять большим пространством. Я предполагаю, что причина упущения может быть в том, что слишком мало людей призывают к методу. Тем не менее, я помню время, когда даже assertFalse не существовало; поэтому у меня есть положительное ожидание, что метод может в конце концов, следует добавить, что это не трудно, хотя я признаю, что существует множество обходных путей, даже изящных.


Я иду на эту вечеринку довольно поздно, но я обнаружил, что в форме:

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

можно заставить работать для большинства случаев "не равно".

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

очевидная причина, по которой люди хотели assertNotEquals (), заключалась в том, чтобы сравнить встроенные элементы без необходимости сначала конвертировать их в полномасштабные объекты:

подробный пример:

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

и

assertNotEqual(1, winningBidderId);

к сожалению, поскольку Eclipse не включает JUnit 4.11 по умолчанию, вы должны быть подробными.

предостережение я не думаю, что " 1 " должен быть завернут в целое число.valueOf () но так как я недавно вернулся из .NET, не рассчитывайте на мою корректность.


Я работаю над JUnit в среде java 8, используя jUnit4.12

для меня: компилятор не смог найти метод assertNotEquals, даже когда я использовал
import org.junit.Assert;

поэтому я изменил
assertNotEquals("addb", string);
to
Assert.assertNotEquals("addb", string);

Итак, если вы столкнулись с проблемой относительно assertNotEqual не распознается, затем измените его на Assert.assertNotEquals(,); это должно решить вашу проблему.


лучше использовать Hamcrest для отрицательных утверждений, а не assertFalse, поскольку в первом отчете теста будет показана разница для отказа утверждения.

Если вы используете assertFalse, вы просто получаете сбой утверждения в отчете. т. е. утеряна информация о причине отказа.


я полностью согласен с точкой зрения OP. Assert.assertFalse(expected.equals(actual)) - это не естественный способ выразить неравенством.
Но я бы сказал, что дальше, чем Assert.assertEquals(), Assert.assertNotEquals() работает, но не является удобным для документирования того, что на самом деле утверждает тест, и для понимания/отладки при сбое утверждения.
Так что да JUnit 4.11 и JUnit 5 обеспечивает Assert.assertNotEquals() (Assertions.assertNotEquals() в JUnit 5), но я действительно избегаю их использования.

как альтернатива, утверждать состояния объекта I Общие использовать matcher API, который легко проникает в состояние объекта, этот документ четко определяет намерение утверждений и очень удобен для пользователя, чтобы понять причину сбоя утверждения.

вот пример.
Предположим у меня есть класс животных, который я хочу проверить createWithNewNameAndAge() метод, метод, который создает новый объект животного путем изменения его имени и возраста, но сохраняя свою любимую пищу.
Предположим, я использую Assert.assertNotEquals() утверждать, что исходные и новые объекты различаться.
Вот класс животных с дефектной реализацией 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+ (или JUnit 5) как тестовый бегун и инструмент утверждения

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

тест завершается неудачей, как и ожидалось, но причина, предоставленная разработчику, действительно не помогает. Он просто говорит, что значения должны быть разными и выводить toString() результат вызывается на фактическом :

java.ленг.AssertionError: значения должны быть разными. Фактическое: Животное

[имя=scoubi, возраст=10, favoriteFood=сено]

в орг.тесты JUnit.Утверждать.fail(Assert.java: 88)

Ok объекты не равны. Но в чем проблема ?
Какое поле неправильно оценено в тестируемом методе ? Один ? Два ? Все ?
Чтобы обнаружить его, вы должны копать в createWithNewNameAndAge() реализация / использование отладчика во время тестирования API было бы гораздо дружелюбнее, если бы это сделало для нас разницу между тем, что ожидается и что получается.


JUnit 4.11 в качестве тестового бегуна и API тестового сопоставления в качестве инструмента утверждения

здесь тот же сценарий теста, но который использует AssertJ (отличный API-интерфейс сопоставления тестов), чтобы сделать утверждение Animal состояние: :

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");
}

конечно, тест все еще терпит неудачу, но на этот раз причина четко указана :

java.ленг.AssertionError:

ожидаем:

содержат именно (и в том же порядке):

но некоторые элементы не были обнаружены:

и других не ожидали:

at junit5.Образом: mytest.assertListNotEquals_AssertJ(образом: mytest.java: 26)

мы можем прочитать, что для Animal::getName, Animal::getAge, Animal::getFavoriteFood значения возвращенного животного, мы ожидаем иметь следующее значение:

"little scoubi", 1, "hay" 

но у нас были такие значения:

"scoubi", 10, "hay"

Итак, мы знаем, где исследуют : name и age неправильно оценены. Кроме того, факт указания hay значение в утверждении Animal::getFavoriteFood() позволяет также более точно утверждать, возвращенный Animal. Мы хотим, чтобы объекты не были одинаковыми для некоторых свойств, но не обязательно для всех свойств.
Поэтому, безусловно, использование API matcher намного более ясно и гибко.


согласованность API по модулю, почему JUnit не предоставил assertNotEquals() является той же причиной, почему JUnit никогда не предоставлял методы, такие как

  • assertStringMatchesTheRegex(regex, str) и assertStringDoesntMatchTheRegex(regex, str)
  • assertStringBeginsWith(prefix, str) и assertStringDoesntBeginWith(prefix, str)

т. е. нет конца предоставлению конкретных методов утверждения для видов вещей, которые вы можете захотеть в своей логике утверждения!

гораздо лучше предоставить составные тестовые примитивы, такие как equalTo(...), is(...), not(...), regex(...) и пусть программист соединяет их вместе для большей читаемости и здравомыслия.