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

StackOverflow https://stackoverflow.com/questions/1096650

  •  11-09-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

Я бы посоветовал вам использовать более новую 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;

Мне интересно то же самое.API Assert не очень симметричен;для проверки того, одинаковы ли объекты, он предоставляет assertSame и assertNotSame.

Конечно, долго писать не придется:

assertFalse(foo.equals(bar));

При таком утверждении единственной информативной частью вывода, к сожалению, является имя тестового метода, поэтому описательное сообщение должно формироваться отдельно:

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

Это, конечно, так утомительно, что лучше самому накатать. assertNotEqual.К счастью, в будущем он, возможно, станет частью JUnit: JUnit, проблема 22

Я бы сказал, что отсутствие 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 ) ;

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

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

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

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

Очевидная причина, по которой люди хотели использовать метод AssertNotEquals(), заключалась в том, чтобы сравнивать встроенные функции без необходимости предварительного преобразования их в полноценные объекты:

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

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

против.

assertNotEqual(1, winningBidderId);

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

Предостережение. Я не думаю, что «1» нужно заключать в Integer.valueOf(), но, поскольку я только что вернулся из .NET, не рассчитывайте на мою правильность.

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

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

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

В качестве альтернативы, чтобы подтвердить состояние объекта, я обычно использую API-интерфейс сопоставления, который легко анализирует состояние объекта, который четко документирует намерение утверждений и очень удобен для пользователя, чтобы понять причину сбоя утверждения.

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

java.lang.AssertionError:Ценности должны быть разными.Действительный:Животное

[name=scoubi, age=10, FavoriteFood=сено]

в org.junit.Assert.fail(Assert.java:88)

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


JUnit 4.11 в качестве средства запуска тестов и API-интерфейс Test Matcher в качестве инструмента утверждения.

Здесь тот же сценарий тестирования, но в нем используется 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.lang.AssertionError:

Ожидание:

<["скуби", 10, "сено"]>

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

<["маленький скуби", 1, "сено"]>

но некоторые элементы не были найдены:

<["маленький скуби", 1]>

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

<["Скуби", 10]>

в 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-интерфейса сопоставления, безусловно, гораздо более понятно и гибко.

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

  • assertStringMatchesTheRegex(regex, str) против. assertStringDoesntMatchTheRegex(regex, str)
  • assertStringBeginsWith(prefix, str) против. assertStringDoesntBeginWith(prefix, str)

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top