Tôi hoàn toàn đồng ý với quan điểm của OP. Assert.assertFalse(expected.equals(actual))
không phải là một cách tự nhiên để thể hiện sự bất bình đẳng.
Nhưng tôi sẽ lập luận rằng xa hơn Assert.assertEquals()
, Assert.assertNotEquals()
hoạt động nhưng không thân thiện với người dùng để ghi lại những gì thử nghiệm thực sự khẳng định và để hiểu / gỡ lỗi khi xác nhận thất bại.
Vì vậy, có JUnit 4.11 và JUnit 5 cung cấp Assert.assertNotEquals()
( Assertions.assertNotEquals()
trong JUnit 5) nhưng tôi thực sự tránh sử dụng chúng.
Thay vào đó, để xác nhận trạng thái của một đối tượng tôi thường sử dụng API đối sánh dễ dàng đào sâu vào trạng thái đối tượng, tài liệu đó rõ ràng là ý định của các xác nhận và rất thân thiện với người dùng để hiểu nguyên nhân của sự thất bại khẳng định.
Đây là một ví dụ.
Giả sử tôi có một lớp Thú mà tôi muốn kiểm tra createWithNewNameAndAge()
phương thức, một phương thức tạo ra một đối tượng Động vật mới bằng cách thay đổi tên và tuổi của nó nhưng bằng cách giữ thức ăn yêu thích của nó.
Giả sử tôi sử dụng Assert.assertNotEquals()
để khẳng định rằng bản gốc và các đối tượng mới là khác nhau.
Đây là lớp Animal với cách thực hiện thiếu sót 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+ (hoặc JUnit 5) vừa là công cụ kiểm tra vừa chạy
@Test
void assertListNotEquals_JUnit_way() {
Animal scoubi = new Animal("scoubi", 10, "hay");
Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
Assert.assertNotEquals(scoubi, littleScoubi);
}
Thử nghiệm thất bại như mong đợi nhưng nguyên nhân cung cấp cho nhà phát triển thực sự không hữu ích. Nó chỉ nói rằng các giá trị phải khác nhau và đưa ra toString()
kết quả được gọi trên Animal
tham số thực tế :
java.lang.AssertsError: Các giá trị phải khác nhau. Thực tế: Động vật
[name = scoubi, age = 10, favourite = hay]
tại org.junit.Assert.fail (Assert.java:88)
Ok các đối tượng không bằng nhau. Nhưng vấn đề ở đâu?
Trường nào không có giá trị chính xác trong phương pháp thử nghiệm? Một ? Hai ? Tất cả bọn họ ?
Để khám phá ra nó, bạn phải đào sâu vào việc createWithNewNameAndAge()
triển khai / sử dụng trình gỡ lỗi trong khi API thử nghiệm sẽ thân thiện hơn nhiều nếu nó tạo cho chúng tôi sự khác biệt giữa dự kiến và dự kiến.
JUnit 4.11 với tư cách là người chạy thử nghiệm và API đối sánh thử nghiệm làm công cụ xác nhận
Ở đây cùng một kịch bản thử nghiệm nhưng sử dụng AssertJ (API đối sánh thử nghiệm tuyệt vời) để đưa ra khẳng định về Animal
trạng thái ::
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");
}
Tất nhiên bài kiểm tra vẫn thất bại nhưng lần này lý do được nêu rõ:
java.lang.AssertsError:
Mong đợi:
<["scoubi", 10, "hay"]>
để chứa chính xác (và theo cùng thứ tự):
<["scoubi nhỏ", 1, "hay"]>
nhưng một số yếu tố không được tìm thấy:
<["scoubi nhỏ", 1]>
và những người khác không mong đợi:
<["Scoubi", 10]>
tại junit5.MyTest.assertListNotEquals_AssertJ (MyTest.java:26)
Chúng ta có thể đọc rằng đối với Animal::getName, Animal::getAge, Animal::getFavoriteFood
các giá trị của Động vật được trả về, chúng ta hy vọng sẽ có các giá trị này:
"little scoubi", 1, "hay"
nhưng chúng tôi đã có những giá trị sau:
"scoubi", 10, "hay"
Vì vậy, chúng tôi biết nơi điều tra: name
và age
không có giá trị chính xác. Ngoài ra, thực tế chỉ định hay
giá trị trong xác nhận Animal::getFavoriteFood()
cho phép cũng xác nhận chính xác hơn trả lại Animal
. Chúng tôi muốn rằng các đối tượng không giống nhau đối với một số thuộc tính nhưng không nhất thiết phải cho mọi thuộc tính.
Vì vậy, chắc chắn, sử dụng API so khớp rõ ràng và linh hoạt hơn nhiều.