Tại sao tôi nên sử dụng Hamcrest-Matcher và assertThat () thay vì assertXXX () - Phương thức truyền thống


153

Khi tôi xem các ví dụ trong lớp Assert JavaDoc

assertThat("Help! Integers don't work", 0, is(1)); // fails:
// failure message:
// Help! Integers don't work
// expected: is <1> 
// got value: <0>
assertThat("Zero is one", 0, is(not(1))) // passes

Tôi không thấy một lợi thế lớn hơn, giả sử , assertEquals( 0, 1 ).

Có thể tốt cho các tin nhắn nếu các cấu trúc trở nên phức tạp hơn nhưng bạn có thấy nhiều lợi thế hơn không? Dễ đọc?

Câu trả lời:


172

Không có lợi thế lớn cho những trường hợp assertFootồn tại phù hợp chính xác với ý định của bạn. Trong những trường hợp họ hành xử gần như giống nhau.

Nhưng khi bạn đến kiểm tra có phần phức tạp hơn, thì lợi thế sẽ trở nên rõ ràng hơn:

assertTrue(foo.contains("someValue") && foo.contains("anotherValue"));

so với

assertThat(foo, hasItems("someValue", "anotherValue"));

Người ta có thể thảo luận xem cái nào dễ đọc hơn, nhưng một khi khẳng định không thành công, bạn sẽ nhận được thông báo lỗi tốt assertThat, nhưng chỉ có một lượng thông tin rất nhỏ từ đó assertTrue.

assertThatsẽ cho bạn biết khẳng định là gì và thay vào đó bạn nhận được gì. assertTruesẽ chỉ cho bạn biết rằng bạn đã có falsenơi bạn mong đợi true.


Tôi đã có câu hỏi này trong tâm trí của tôi. Cảm ơn bạn, tôi không bao giờ nghĩ về nó theo cách này.
Wheaties

1
Nó cũng giúp với "quy tắc" của một xác nhận cho mỗi thử nghiệm và pha trộn dễ dàng hơn với các thông số kỹ thuật theo kiểu BDD.
Nils Wloka

2
Và nó tách cơ chế xác nhận khỏi điều kiện (đó là những gì dẫn đến các thông báo lỗi tốt hơn).
SteveD

2
Ví dụ này là không hợp lý vì hầu như không ai sẽ sử dụng một assertTruevới một &&. Việc tách nó thành hai điều kiện làm cho vấn đề trở nên rõ ràng ngay cả trong JUnit. Đừng hiểu lầm tôi; Tôi đồng ý với bạn, tôi chỉ không thích ví dụ của bạn.
maaartinus

48

Ghi chú phát hành JUnit cho phiên bản 4.4 (nơi được giới thiệu) nêu lên bốn ưu điểm:

  • Dễ đọc và dễ đánh máy hơn: cú pháp này cho phép bạn suy nghĩ về chủ đề, động từ, đối tượng (khẳng định "x là 3") thay vì assertEquals , sử dụng động từ, đối tượng, chủ đề (khẳng định "bằng 3 x")
  • Kết hợp: bất kỳ câu lệnh so khớp nào cũng có thể bị phủ định ( không (s) ), kết hợp ( hoặc (s) .or (t) ), được ánh xạ tới một bộ sưu tập ( mỗi (s) ) hoặc được sử dụng trong các kết hợp tùy chỉnh ( afterFiveSeconds (s) )
  • Thông báo thất bại có thể đọc được. (...)
  • Ghép nối tùy chỉnh. Bằng cách tự mình thực hiện giao diện Matcher , bạn có thể nhận được tất cả các lợi ích trên cho các xác nhận tùy chỉnh của riêng bạn.

Lập luận chi tiết hơn từ anh chàng đã tạo ra cú pháp mới: tại đây .


39

Về cơ bản để tăng khả năng đọc của mã .

Bên cạnh hamcrest, bạn cũng có thể sử dụng các xác nhận lễ hội . Họ có một vài lợi thế so với hamcrest như:

Vài ví dụ

import static org.fest.assertions.api.Assertions.*;

// common assertions
assertThat(yoda).isInstanceOf(Jedi.class);
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);
assertThat(frodo).isIn(fellowshipOfTheRing);
assertThat(sauron).isNotIn(fellowshipOfTheRing);

// String specific assertions
assertThat(frodo.getName()).startsWith("Fro").endsWith("do")
                           .isEqualToIgnoringCase("frodo");

// collection specific assertions
assertThat(fellowshipOfTheRing).hasSize(9)
                               .contains(frodo, sam)
                               .excludes(sauron);


// map specific assertions (One ring and elves ring bearers initialized before)
assertThat(ringBearers).hasSize(4)
                       .includes(entry(Ring.oneRing, frodo), entry(Ring.nenya, galadriel))
                       .excludes(entry(Ring.oneRing, aragorn));

Cập nhật ngày 17 tháng 10 năm 2016

Fest không hoạt động nữa, thay vào đó hãy sử dụng AssertJ .


4
Fest dường như đã chết, nhưng ngã ba AssertJ còn sống rất nhiều.
Amedee Van Gasse

18

Một lời biện minh rất cơ bản là khó có thể làm rối cú pháp mới.

Giả sử rằng một giá trị cụ thể, foo, phải là 1 sau khi kiểm tra.

assertEqual(1, foo);

--HOẶC LÀ--

assertThat(foo, is(1));

Với cách tiếp cận đầu tiên, rất dễ quên thứ tự chính xác và gõ ngược lại. Sau đó, thay vì nói rằng bài kiểm tra thất bại vì nó dự kiến ​​1 và có 2, tin nhắn bị ngược. Không phải là một vấn đề khi thử nghiệm vượt qua, nhưng có thể dẫn đến nhầm lẫn khi thử nghiệm thất bại.

Với phiên bản thứ hai, gần như không thể mắc lỗi này.


... và khi Eclipse báo cáo lỗi xác nhận, nếu bạn đặt các đối số sai vòng trong khẳng định truyền thống (), thì lỗi không có nghĩa.
Sridhar Sarnobat

9

Thí dụ:

assertThat(5 , allOf(greaterThan(1),lessThan(3)));
//  java.lang.AssertionError:
//  Expected: (a value greater than <1> and a value less than <3>)
//       got: <5>
assertTrue("Number not between 1 and 3!", 1 < 5 && 5 < 3);
//  java.lang.AssertionError: Number not between 1 and 3!
  1. bạn có thể làm cho bài kiểm tra của bạn cụ thể hơn
  2. bạn nhận được một Ngoại lệ chi tiết hơn, nếu các bài kiểm tra thất bại
  3. dễ dàng hơn để đọc bài kiểm tra

btw: bạn cũng có thể viết Văn bản trong assertXXX ...


1
Tốt hơn nữa, tôi sẽ loại bỏ đối số chuỗi trong assertThattrường hợp này, vì thông báo bạn nhận được tự động chỉ là thông tin: "Dự kiến: (giá trị lớn hơn <1> và giá trị nhỏ hơn <3>)"
MatrixFrog

Vâng, bạn đúng. Tôi chỉnh sửa câu trả lời của tôi. Về cơ bản, tôi muốn sử dụng cả (Matcher) .and (Matcher) nhưng nó không hoạt động.
MartinL

3
assertThat(frodo.getName()).isEqualTo("Frodo");

Gần với ngôn ngữ tự nhiên.

Dễ đọc hơn, phân tích mã dễ dàng hơn. Lập trình viên dành nhiều thời gian để phân tích mã hơn là viết mã mới. Vì vậy, nếu mã sẽ dễ dàng phân tích thì nhà phát triển sẽ có năng suất cao hơn.

Mã PS nên được viết tốt như cuốn sách. Mã tài liệu tự.


4
Được rồi và…? Tôi khuyên bạn nên ủng hộ lập luận của mình bằng cách giải thích lý do tại sao đó là một điều tốt.
Nathan Tuggy

0

Có những lợi thế để khẳng định. Hơn so với assertEquals -
1) dễ đọc hơn
2) thông tin thêm về thất bại
3) biên dịch lỗi thời gian - thay vì lỗi thời gian chạy
4) linh hoạt với điều kiện kiểm tra viết
5) di động - nếu bạn đang sử dụng hamcrest - bạn có thể sử dụng jUnit hoặc TestNG làm khung cơ bản.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.