เหตุใดฉันจึงควรใช้ Hamcrest-Matcher และ assertThat () แทน assertXXX แบบดั้งเดิม () - วิธีการ


153

เมื่อฉันดูตัวอย่างในคลาส 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

assertEquals( 0, 1 )ฉันไม่ได้เห็นข้อได้เปรียบใหญ่กว่าสมมติว่า

มันอาจจะดีสำหรับข้อความถ้าโครงสร้างมีความซับซ้อนมากขึ้น แต่คุณเห็นข้อดีมากกว่านี้ไหม? การอ่าน?

คำตอบ:


173

ไม่มีประโยชน์ใหญ่สำหรับกรณีที่มีassertFooอยู่ที่ตรงกับความตั้งใจของคุณ ในกรณีเหล่านั้นพวกเขาทำงานเกือบเหมือนกัน

แต่เมื่อคุณมาตรวจสอบที่ค่อนข้างซับซ้อนกว่าประโยชน์จะกลายเป็นชัดเจน:

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

เมื่อเทียบกับ

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

หนึ่งสามารถพูดคุยซึ่งหนึ่งในนั้นคือง่ายต่อการอ่าน แต่เมื่อยืนยันล้มเหลวคุณจะได้รับข้อความแสดงข้อผิดพลาดที่ดีจากแต่เพียงจำนวนน้อยมากของข้อมูลจากassertThatassertTrue

assertThatจะบอกคุณว่าการยืนยันนั้นเป็นอย่างไรและคุณได้อะไรมาแทน assertTrueเท่านั้นที่จะบอกคุณว่าคุณได้ที่คุณคาดหวังfalsetrue


ฉันมีคำถามนี้ในใจของฉันด้วย ขอบคุณฉันไม่เคยคิดในลักษณะนี้
ข้าวสาลี

1
นอกจากนี้ยังช่วยในการ "กฎ" ของการยืนยันหนึ่งครั้งต่อการทดสอบและผสมผสานได้ง่ายขึ้นด้วยข้อมูลจำเพาะสไตล์ BDD
Nils Wloka

2
และมันแยกกลไกการยืนยันออกจากเงื่อนไข (ซึ่งเป็นสิ่งที่นำไปสู่ข้อความแสดงข้อผิดพลาดที่ดีกว่า)
SteveD

2
ตัวอย่างคือไม่น่าเชื่อว่าเป็นใครแทบจะไม่จะใช้เป็นหนึ่งเดียวกับassertTrue &&การแยกออกเป็นสองเงื่อนไขทำให้เกิดปัญหาชัดเจนแม้ใน JUnit อย่าเข้าใจฉันผิด ฉันเห็นด้วยกับคุณฉันไม่ชอบตัวอย่างของคุณ
maaartinus

48

บันทึกย่อรีลีส JUnit สำหรับเวอร์ชัน 4.4 (ซึ่งเป็นที่แนะนำ) ระบุข้อดีสี่ประการ:

  • อ่านได้ง่ายขึ้นและพิมพ์ได้: ไวยากรณ์นี้ช่วยให้คุณคิดในแง่ของหัวเรื่อง, กริยา, วัตถุ (assert "x is 3") แทนassertEqualsซึ่งใช้กริยา, วัตถุ, หัวเรื่อง (assert "เท่ากับ 3 x")
  • ชุดค่าผสม: คำสั่งจับคู่ใด ๆ ที่สามารถคัดค้าน ( ไม่ใช่ (s) ), รวม ( อย่างใดอย่างหนึ่ง (s). หรือ (t) ), แมปไปยังคอลเลกชัน ( แต่ละรายการ)หรือใช้ในชุดค่าผสมที่กำหนดเอง ( afterFiveSeconds )
  • ข้อความล้มเหลวที่สามารถอ่านได้ ( ... )
  • Custom Matchers ด้วยการใช้อินเทอร์เฟซMatcherด้วยตัวคุณเองคุณจะได้รับผลประโยชน์ทั้งหมดข้างต้นสำหรับการยืนยันที่คุณกำหนดเอง

รายละเอียดเพิ่มเติมการโต้แย้งจากผู้ชายที่สร้างไวยากรณ์ใหม่ที่นี่


39

โดยทั่วไปสำหรับการเพิ่มความสามารถในการอ่านของรหัส

นอกจาก hamcrest คุณยังสามารถใช้ยืนยันเทศกาล พวกเขามีข้อได้เปรียบบางประการเกี่ยวกับ hamcrestเช่น:

ตัวอย่างบางส่วน

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));

อัปเดตเมื่อวันที่ 17 ตุลาคม 2559

Fest ไม่ได้ใช้งานอีกต่อไปให้ใช้AssertJแทน


4
ดูเหมือนว่า Fest จะตาย แต่ Fork AssertJ ยังมีชีวิตอยู่เป็นอย่างมาก
Amedee Van Gasse

18

เหตุผลพื้นฐานมากคือมันยากที่จะทำให้สับสนไวยากรณ์ใหม่

สมมติว่าค่าเฉพาะ foo ควรเป็น 1 หลังจากการทดสอบ

assertEqual(1, foo);

--หรือ--

assertThat(foo, is(1));

ด้วยวิธีแรกมันง่ายมากที่จะลืมลำดับที่ถูกต้องและพิมพ์ไปข้างหลัง จากนั้นแทนที่จะบอกว่าการทดสอบล้มเหลวเพราะคาดว่าจะได้ 1 และได้รับ 2 ข้อความจะถอยหลัง ไม่ใช่ปัญหาเมื่อการทดสอบผ่าน แต่อาจทำให้เกิดความสับสนเมื่อการทดสอบล้มเหลว

ด้วยรุ่นที่สองมันแทบจะเป็นไปไม่ได้ที่จะทำผิดพลาดนี้


... และเมื่อ Eclipse รายงานความล้มเหลวในการยืนยันหากคุณใส่อาร์กิวเมนต์ผิดวิธีใน assert ดั้งเดิมนั่นคือ () ข้อผิดพลาดไม่สมเหตุสมผล
Sridhar Sarnobat

9

ตัวอย่าง:

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. คุณสามารถทำการทดสอบเพิ่มเติมโดยเฉพาะ
  2. คุณจะได้รับข้อยกเว้นที่ละเอียดกว่านี้หากการทดสอบล้มเหลว
  3. ง่ายต่อการอ่านการทดสอบ

btw: คุณสามารถเขียนข้อความใน assertXXX ได้เช่นกัน ...


1
ยังดีกว่าฉันจะทิ้งอาร์กิวเมนต์สตริงในassertThatกรณีเนื่องจากข้อความที่คุณได้รับโดยอัตโนมัติเป็นเพียงข้อมูล: "คาดหวัง: (ค่ามากกว่า <1> และค่าน้อยกว่า <3>)"
MatrixFrog

ใช่คุณถูก. ฉันแก้ไขคำตอบของฉัน เดิมฉันต้องการใช้ทั้งคู่ (Matcher) และ (Matcher) แต่มันใช้ไม่ได้
MartinL

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

อยู่ใกล้กับภาษาธรรมชาติ

อ่านง่ายขึ้นวิเคราะห์โค้ดได้ง่ายขึ้น โปรแกรมเมอร์ใช้เวลาในการวิเคราะห์โค้ดมากกว่าเขียนใหม่ ดังนั้นหากรหัสจะวิเคราะห์ได้ง่ายนักพัฒนาซอฟต์แวร์ควรมีประสิทธิผลมากกว่า

รหัส PS ควรเป็นหนังสือที่เขียนดี รหัสเอกสารด้วยตนเอง


4
ตกลงและ…? ฉันขอแนะนำให้สนับสนุนการโต้แย้งของคุณโดยอธิบายว่าทำไมสิ่งนี้ถึงดี
นาธาน Tuggy

0

มีข้อดีที่จะยืนยันว่า assertEquals -
1) อ่านได้มากขึ้น
2) ข้อมูลเพิ่มเติมเกี่ยวกับความล้มเหลว
3) ข้อผิดพลาดเวลารวบรวม - มากกว่าข้อผิดพลาดเวลาทำงาน
4) ความยืดหยุ่นกับการเขียนเงื่อนไขการทดสอบ
5) แบบพกพา - ถ้าคุณใช้ Hamcrest หรือ TestNG เป็นเฟรมเวิร์กพื้นฐาน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.