有没有人知道为什么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()
的问题。 - sehassertNotEqual
”,我认为这是因为它是一种专门的断言,不像assertEquals
那样经常需要,因此可以通过通用的assertFalse
来表达。 - Joachim SauerassertThat
比assert*
更具表现力,但我认为它通常不比你可以放在assert*
表达式内外的Java表达式更具表现力(毕竟,我可以用Java代码表达任何东西)。这是我开始遇到流畅式API的一个普遍问题 - 每一个都基本上是一个新的DSL,你必须学习它(当我们已经知道Java语言时!)。我想Hamcrest现在已经足够普及,可以合理地期望人们知道它。我会去试试看... - bacarimport static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
- fIwJlxSzApHEZIlJUnit 4.11 中有一个 assertNotEquals
:https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume
import static org.junit.Assert.assertNotEquals;
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 ) ;
我正在java 8环境下使用jUnit4.12处理JUnit。
对于我来说:即使我使用了import org.junit.Assert;
,编译器也无法找到方法assertNotEquals。
所以我将assertNotEquals("addb", string);
改为Assert.assertNotEquals("addb", string);
因此,如果你遇到关于assertNotEqual
未被识别的问题,请将其更改为Assert.assertNotEquals(,);
它应该解决你的问题。
import static org.junit.Assert.*;
,你就可以在不使用类名的情况下使用所有的断言。 - Tom Stone....
assertThat(1, not(equalTo(Integer.valueOf(winningBidderId))));
....
对比。
assertNotEqual(1, winningBidderId);
遗憾的是,由于Eclipse默认不包含JUnit 4.11,所以您必须详细说明。
注意:我认为'1'不需要用Integer.valueOf()包装,但由于我刚从.NET回来,所以请勿指望我的正确性。
assertTrue(obj1.equals(obj2));
并且:
assertFalse(obj1.equals(obj2));
当它们被期望是不相等的时候。我知道这不是你问题的答案,但这是我能得到的最接近的答案。它可以帮助那些在JUnit 4.11之前版本中寻找可以做什么的人。
使用Hamcrest来进行负面断言比使用assertFalse更好,因为前者在测试报告中显示故障的区别。
如果您使用assertFalse,您只会在报告中得到一个断言失败。即失败原因丢失了相关信息。
我完全同意 OP 的观点。 Assert.assertFalse(expected.equals(actual))
不是一种自然的表达不等式的方式。
但是,我会认为除了 Assert.assertEquals()
之外,Assert.assertNotEquals()
也可以使用,但不利于记录测试实际断言的内容以及理解/调试,因为断言失败后不容易理解。
所以,是的,JUnit 4.11 和 JUnit 5 提供了 Assert.assertNotEquals()
(在 JUnit 5 中是 Assertions.assertNotEquals()
),但我真的避免使用它们。
作为替代方案,为了断言对象的状态,我通常会使用一个匹配器 API,它可以轻松地深入对象状态,清楚地记录断言的意图,并且非常用户友好,以便了解断言失败的原因。
这里是一个例子。
假设我有一个 Animal 类,我要测试其 createWithNewNameAndAge()
方法,该方法通过更改其名称和年龄而创建一个新的 Animal 对象,但保留其喜欢的食物。
假设我使用 Assert.assertNotEquals()
来断言原始对象和新对象不同。
这是 Animal 类的一个 flawed 实现的 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);
}
测试结果如预期般失败,但给开发人员的原因并不是很有帮助。它只是说值应该不同,并输出在实际Animal
参数上调用的toString()
结果:
java.lang.AssertionError: 值应该不同。实际值:Animal
[name=scoubi, age=10, favoriteFood=hay]
at org.junit.Assert.fail(Assert.java:88)
好的,对象确实不相等。但问题出在哪里?
在被测试方法中,哪一个字段的值没有正确设置?一个字段?两个字段?还是全部字段?
要找出答案,你需要深入研究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");
}
"little scoubi", 1, "hay"
但我们已经有了这些值:
"scoubi", 10, "hay"
所以我们知道要调查的地方:name
和age
的值不正确。
此外,在Animal::getFavoriteFood()
的断言中指定hay
值,也可以更精细地断言返回的Animal
。我们希望对象在某些属性上不相同,但不一定在每个属性上都不同。
因此,使用匹配器API明显更清晰、更灵活。
assertEquals
和assertNotEquals
。 https://www.codingeek.com/tutorials/junit/a-complete-guide-to-junit-with-java-and-gradle/#6_assertions - Hitesh Garg