有人知道为什么JUnit 4提供 assertEquals(foo,bar)
但不assertNotEqual(foo,bar)
方法吗?
它提供了assertNotSame
(对应于assertSame
)和assertFalse
(对应于assertTrue
),因此它们似乎没有包含在内就显得很奇怪assertNotEqual
。
顺便说一句,我知道JUnit插件提供了我正在寻找的方法。我只是出于好奇而问。
有人知道为什么JUnit 4提供 assertEquals(foo,bar)
但不assertNotEqual(foo,bar)
方法吗?
它提供了assertNotSame
(对应于assertSame
)和assertFalse
(对应于assertTrue
),因此它们似乎没有包含在内就显得很奇怪assertNotEqual
。
顺便说一句,我知道JUnit插件提供了我正在寻找的方法。我只是出于好奇而问。
Answers:
我建议您使用较新的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()
。
assertNotEqual
”,我想说这是因为它是一个专门的断言,不需要那么频繁assertEquals
,因此可以通过泛型来表示assertFalse
。
assertThat
,与assert*
可用的有限方法相比,它更具表达力。因此,您可以在一行中表达确切的约束,使其(几乎)像英语句子一样阅读, 并在断言失败时获得有意义的消息。当然,这并不总是一个杀手级功能,但是当您几次看到它在行动中时,您会看到它增加了多少价值。
assertThat
比更具表达力assert*
,但是我不认为它比您可以在表达式内外添加的Java表达式更具表达assert*
力(毕竟我可以用Java代码表达任何东西)。我已经开始遇到流利风格的API,这是一个普遍的问题-每个基本都是您必须学习的新DSL(当我们都已经知道Java的时候!)。我认为Hamcrest现在已经无处不在,可以期望人们知道了。我会玩...
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不是很对称。为了测试对象是否相同,它提供了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 ) ;
我正在使用jUnit4.12在Java 8环境中开发JUnit
对我来说:即使我使用了编译器,也无法找到方法assertNotEquals
import org.junit.Assert;
所以我改变了assertNotEquals("addb", string);
对Assert.assertNotEquals("addb", string);
因此,如果您遇到有关assertNotEqual
无法识别的问题,则将其更改为Assert.assertNotEquals(,);
它可以解决您的问题
import static org.junit.Assert.*;
,您将可以使用没有类名的所有断言。
我完全同意OP的观点。 Assert.assertFalse(expected.equals(actual))
这是表达不平等现象的自然方法。
但是,我认为,除了以外Assert.assertEquals()
,还 Assert.assertNotEquals()
可以工作,但对记录测试实际断言并在断言失败时进行理解/调试不友好。
所以是的,JUnit 4.11和JUnit 5提供了Assert.assertNotEquals()
(Assertions.assertNotEquals()
在JUnit 5中),但我确实避免使用它们。
作为替代,要声明一个对象的状态,我通常使用一个匹配器API,该API可以轻松地深入到该对象的状态,该文件清楚地记录了声明的意图,并且非常便于用户理解声明失败的原因。
这是一个例子。
假设我有一个Animal类,我想测试该createWithNewNameAndAge()
方法,该方法通过更改名称和使用年龄但保留其喜欢的食物来创建新的Animal对象。
假设我曾经 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()
在实际Animal
参数上调用的结果:
java.lang.AssertionError:值应该不同。实际:动物
[名称= scoubi,年龄= 10,最喜欢的食物=干草]
在org.junit.Assert.fail(Assert.java:88)
好的,对象不相等。但是问题出在哪里呢?
在测试方法中哪个字段的值不正确?一个?两个?他们全部 ?
要发现它,您必须深入研究createWithNewNameAndAge()
实现/使用调试器,而如果测试API对我们而言可以期望和获得之间的差异,则它会更加友好。
使用JUnit 4.11作为测试运行程序,并使用测试Matcher 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.lang.AssertionError:
期望:
<[“ scoubi”,10,“干草”]>
完全包含(并以相同顺序):
<[“小顽童”,1,“干草”]>
但未找到一些元素:
<[“小巧”,1]>
并没有其他预期:
<[“ scoubi”,10]>
在junit5.MyTest.assertListNotEquals_AssertJ(MyTest.java:26)
我们可以看到,对于Animal::getName, Animal::getAge, Animal::getFavoriteFood
返回的Animal的值,我们希望具有以下值:
"little scoubi", 1, "hay"
但是我们有这些值:
"scoubi", 10, "hay"
因此,我们知道在哪里调查:,name
并且age
价值不正确。此外,hay
在的声明中指定值的事实Animal::getFavoriteFood()
还允许更精细地声明返回的Animal
。我们希望某些属性的对象不相同,但并非每个属性都相同。
因此,毫无疑问,使用Matcher API更加清晰和灵活。
Modulo API的一致性,为什么JUnit不提供assertNotEquals()
与JUnit从未提供类似方法的原因相同
assertStringMatchesTheRegex(regex, str)
与 assertStringDoesntMatchTheRegex(regex, str)
assertStringBeginsWith(prefix, str)
与 assertStringDoesntBeginWith(prefix, str)
也就是说,为您可能在断言逻辑中想要的事情提供特定的断言方法是没有止境的!
远东更好地提供组合的测试原语一样equalTo(...)
,is(...)
,not(...)
,regex(...)
并让程序员一块那些一起,而不是更多的可读性和理智。