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
10 回答
最好将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()
断言原始对象和新对象是不同的 .这是具有
createWithNewNameAndAge()
的有缺陷实现的Animal类:JUnit 4.11+ (or JUnit 5) both as test runner and assertion tool
测试按预期失败,但提供给开发人员的原因实际上没有帮助 . 它只是说值应该不同并输出在实际
Animal
参数上调用的toString()
结果:好吧,对象不等于 . 但问题出在哪里?
在测试方法中哪个字段没有正确估值?一个?两个?他们都是 ?
要发现它,你必须深入研究
createWithNewNameAndAge()
实现/使用调试器,而测试API会更友好,如果它能使我们之间的差异是预期,哪些得到了 .JUnit 4.11 as test runner and a test Matcher API as assertion tool
这里是相同的测试场景,但使用AssertJ(一个优秀的测试匹配器API)来断言
Animal
状态::当然测试仍然失败,但这次原因清楚地说明了:
我们可以读取返回的Animal的
Animal::getName, Animal::getAge, Animal::getFavoriteFood
值,我们希望有这些值:但我们有这些 Value 观:
所以我们知道调查的地方:
name
和age
没有正确估价 . 此外,在Animal::getFavoriteFood()
的断言中指定hay
值的事实也允许更精细地断言返回的Animal
. 我们希望对象对于某些属性不同,但不一定对每个属性都相同 .所以,使用匹配器API更加清晰和灵活 .
我建议你使用更新的assertThat()样式断言,它可以很容易地描述所有类型的否定,并自动构建一个描述你期望的和断言失败时得到的东西:
所有三个选项都是等效的,选择您认为最易读的选项 .
要使用方法的简单名称(并允许此时态语法工作),您需要以下导入:
JUnit 4.11中有
assertNotEquals
:https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume我不知道 . Assert的API不是很对称;为了测试对象是否相同,它提供
assertSame
和assertNotSame
.当然,写作时间不会太长:
有了这样的断言,输出的唯一信息部分遗憾的是测试方法的名称,因此描述性消息应该单独形成:
这当然是如此乏味,最好滚动你自己的
assertNotEqual
. 幸运的是,将来它可能是JUnit的一部分:JUnit issue 22我认为缺少assertNotEqual确实是不对称的,并且使JUnit的学习成果不那么容易 . 请注意,添加方法时这是一个简洁的案例会降低API的复杂性,至少对我而言:对称性有助于统治更大的空间 . 我的猜测是遗漏的原因可能是人们要求这种方法的人太少了 . 然而,我记得甚至断言不存在的时候;因此,我有一个积极的期望,最终可能会添加该方法,因为它不是一个困难的方法;即使我承认有很多变通方法,甚至是优雅的变通办法 .
我很晚才参加这个派对,但我发现这个形式:
可以使其适用于大多数“不平等”的案件 .
人们想要assertNotEquals()的明显原因是比较内置函数而不必先将它们转换为完整的对象:
详细的例子:
与
遗憾的是,由于Eclipse默认情况下不包含JUnit 4.11,因此您必须详细 .
警告我不认为'1'需要包含在Integer.valueOf()中,但由于我是从.NET返回的,所以不要指望我的正确性 .
我正在使用jUnit4.12在java 8环境中使用JUnit
对我来说:即使我使用,编译器也无法找到assertNotEquals方法
import org.junit.Assert;
所以我改变了
assertNotEquals("addb", string);
至
Assert.assertNotEquals("addb", string);
因此,如果您遇到有关
assertNotEqual
无法识别的问题,请将其更改为Assert.assertNotEquals(,);
它应该可以解决您的问题Modulo API一致性,为什么JUnit没有提供
assertNotEquals()
,这与JUnit从未提供类似方法的原因相同assertStringMatchesTheRegex(regex, str)
与assertStringDoesntMatchTheRegex(regex, str)
assertStringBeginsWith(prefix, str)
与assertStringDoesntBeginWith(prefix, str)
也就是说,为断言逻辑中你可能想要的东西提供特定的断言方法是没有意义的!
更好的是提供可组合的测试原语,如
equalTo(...)
,is(...)
,not(...)
,regex(...)
,让程序员将这些组合在一起,以获得更多的可读性和理智性 .