มันสมเหตุสมผลหรือไม่ที่จะวัดความครอบคลุมตามเงื่อนไขสำหรับโค้ด Java 8?


19

ฉันสงสัยว่าการวัดการครอบคลุมโค้ดตามเงื่อนไขด้วยเครื่องมือปัจจุบันสำหรับ Java นั้นไม่ล้าสมัยหรือไม่นับตั้งแต่ Java 8 ออกมา ด้วย Java 8's OptionalและStreamเราสามารถหลีกเลี่ยงโค้ดย่อย / ลูปได้ซึ่งทำให้ง่ายต่อการได้รับความคุ้มครองตามเงื่อนไขสูงมากโดยไม่ต้องทดสอบพา ธ การประมวลผลที่เป็นไปได้ทั้งหมด ลองเปรียบเทียบโค้ด Java เก่ากับโค้ด Java 8:

ก่อน Java 8:

public String getName(User user) {
    if (user != null) {
        if (user.getName() != null) {
            return user.getName();
        }
    }
    return "unknown";
}

มี 3 เส้นทางการประมวลผลที่เป็นไปได้ในวิธีการข้างต้น เพื่อให้ได้ความคุ้มครองตามเงื่อนไข 100% เราจำเป็นต้องสร้างการทดสอบ 3 ชุด

Java 8:

public String getName(User user) {
    return Optional.ofNullable(user)
                   .map(User::getName)
                   .orElse("unknown");
}

ในกรณีนี้สาขาถูกซ่อนไว้และเราต้องการเพียง 1 การทดสอบเพื่อให้ได้ความคุ้มครอง 100% และไม่สำคัญว่าเราจะทดสอบกรณีใด แม้ว่าฉันจะยังคงมี 3 สาขาตรรกะเดียวกันซึ่งฉันควรจะครอบคลุม ฉันคิดว่ามันทำให้สถิติความครอบคลุมตามเงื่อนไขไม่น่าเชื่อถืออย่างสมบูรณ์ในทุกวันนี้

มันสมเหตุสมผลหรือไม่ที่จะวัดความครอบคลุมตามเงื่อนไขสำหรับโค้ด Java 8? มีเครื่องมืออื่น ๆ ที่จำรหัสได้หรือไม่?


5
ตัวชี้วัดความคุ้มครองได้ไม่เคยรับเป็นวิธีที่ดีเพื่อตรวจสอบว่ารหัสของคุณเป็นอย่างดีผ่านการทดสอบเพียงวิธีการตรวจสอบสิ่งที่ยังไม่ได้รับการทดสอบ นักพัฒนาที่ดีจะคิดในหลาย ๆ กรณีในใจของเธอและออกแบบการทดสอบสำหรับพวกเขาทั้งหมด - หรืออย่างน้อยที่สุดสิ่งที่เธอคิดว่ามีความสำคัญ
kdgregory

3
แน่นอนว่าการรายงานข่าวที่มีเงื่อนไขสูงไม่ได้หมายความว่าเรามีการทดสอบที่ดี แต่ฉันคิดว่าเป็นประโยชน์อย่างมากที่จะได้รู้ว่าเส้นทางการดำเนินการใดถูกเปิดเผยและนี่คือสิ่งที่คำถามส่วนใหญ่เกี่ยวข้อง โดยไม่มีการครอบคลุมตามเงื่อนไขมันเป็นเรื่องยากมากที่จะระบุสถานการณ์ที่ยังไม่ทดลอง เกี่ยวกับเส้นทาง: [ผู้ใช้: null], [ผู้ใช้: notnull, user.name:null], [ผู้ใช้: notnull, ชื่อผู้ใช้: notnull] ฉันกำลังคิดถึงอะไร
Karol Lewandowski

6
สัญญาของgetNameอะไร มันน่าจะเป็นว่าถ้าuserเป็นโมฆะก็ควรกลับ "ไม่ทราบ" หากuserไม่ใช่โมฆะและuser.getName()เป็นโมฆะมันควรกลับ "ไม่ทราบ" หากuserไม่ใช่โมฆะและuser.getName()ไม่เป็นโมฆะก็ควรคืนค่านั้น ดังนั้นคุณจะทดสอบหน่วยทั้งสามกรณีเพราะนั่นคือสัญญาที่getNameเกี่ยวข้อง คุณดูเหมือนจะทำมันย้อนหลัง คุณไม่ต้องการเห็นสาขาและเขียนการทดสอบตามที่คุณต้องการที่จะเขียนการทดสอบของคุณตามสัญญาของคุณและให้แน่ใจว่าสัญญาเต็ม นั่นคือเมื่อคุณมีความคุ้มครองที่ดี
Vincent Savard

1
อีกครั้งฉันไม่ได้บอกว่าความครอบคลุมได้พิสูจน์แล้วว่ารหัสของฉันได้รับการทดสอบอย่างสมบูรณ์แบบ แต่เป็นเครื่องมือที่มีค่าอย่างยิ่งที่จะแสดงสิ่งที่ฉันยังไม่ได้ทดสอบอย่างแน่นอน ฉันคิดว่าสัญญาทดสอบแยกออกไม่ได้จากการทดสอบเส้นทางการดำเนินการ (ตัวอย่างของคุณยอดเยี่ยมเนื่องจากเกี่ยวข้องกับกลไกทางภาษาโดยปริยาย) หากคุณยังไม่ได้ทดสอบเส้นทางแสดงว่าคุณยังไม่ได้ทดสอบสัญญาอย่างสมบูรณ์หรือสัญญาไม่ได้ถูกกำหนดไว้อย่างสมบูรณ์
Karol Lewandowski

2
ฉันจะทำซ้ำจุดก่อนหน้าของฉัน: เป็นกรณีนี้เสมอเว้นแต่คุณจะ จำกัด ตัวเองเฉพาะคุณลักษณะภาษาขั้นพื้นฐานและไม่เคยเรียกใช้ฟังก์ชันใด ๆ ที่ไม่ได้รับการบันทึก ซึ่งหมายความว่าไม่มีไลบรารีของบุคคลที่สามและไม่ใช้ SDK
kdgregory

คำตอบ:


4

มีเครื่องมือใดบ้างที่ใช้วัดสาขาตรรกะที่สามารถสร้างขึ้นใน Java 8 ได้หรือไม่?

ฉันไม่รู้อะไรเลย ฉันพยายามเรียกใช้รหัสที่คุณมีผ่าน JaCoCo (aka EclEmma) เพื่อให้แน่ใจ แต่มันแสดงให้เห็นถึง 0 สาขาในOptionalรุ่น ฉันไม่รู้วิธีการกำหนดค่าให้พูดอย่างอื่น หากคุณกำหนดค่าให้รวมไฟล์ JDK มันจะแสดงสาขาในทางทฤษฎีOptionalแต่ฉันคิดว่ามันคงโง่ที่จะเริ่มตรวจสอบรหัส JDK คุณเพียงแค่ต้องถือว่ามันถูกต้อง

ฉันคิดว่าประเด็นหลักคือการตระหนักว่าสาขาเพิ่มเติมที่คุณเคยมีมาก่อนหน้าจาวา 8 นั้นเป็นสาขาที่สร้างขึ้นด้วยความรู้สึกปลอม การที่พวกเขาไม่มีอยู่ใน Java 8 นั้นหมายความว่าตอนนี้คุณมีเครื่องมือที่เหมาะสมสำหรับงาน (ในกรณีนี้Optional) ในโค้ด pre-Java 8 คุณต้องเขียนการทดสอบหน่วยพิเศษเพื่อให้คุณมั่นใจได้ว่าโค้ดแต่ละสาขาทำงานในลักษณะที่ยอมรับได้ - และนี่จะมีความสำคัญมากขึ้นในส่วนของโค้ดที่ไม่น่าสนใจเช่นUser/ getNameตัวอย่าง.

ในโค้ด Java 8 คุณจะต้องมั่นใจใน JDK ว่าโค้ดนั้นทำงานได้อย่างถูกต้อง ตามที่คุณควรปฏิบัติต่อOptionalบรรทัดนั้นเช่นเดียวกับเครื่องมือที่ครอบคลุมรหัสปฏิบัติกับมัน: 3 บรรทัดที่มี 0 สาขา ว่ามีสายอื่น ๆ และสาขาในรหัสข้างล่างนี้เป็นสิ่งที่คุณเพียงแค่ไม่ได้ให้ความสนใจกับก่อน แต่มีอยู่ทุกครั้งที่คุณได้บางสิ่งบางอย่างที่ใช้เหมือนหรือArrayListHashMap


2
"ว่ามันไม่มีอยู่ใน Java 8 ... " - ฉันไม่เห็นด้วย Java 8 นั้นใช้งานได้แบบย้อนหลังifและnullยังเป็นส่วนหนึ่งของภาษา ;-) มันยังคงเป็นไปได้ที่จะเขียนโค้ดในแบบเก่าและผ่านnullผู้ใช้หรือผู้ใช้ที่มีnullชื่อ การทดสอบของคุณควรพิสูจน์ว่าสัญญาเป็นไปตามที่คำนึงถึงวิธีการใช้งาน ประเด็นก็คือไม่มีเครื่องมือที่จะบอกคุณว่าคุณได้ทดสอบสัญญาอย่างสมบูรณ์แล้วหรือไม่
Karol Lewandowski

1
@ KarolLewandowski ฉันคิดว่าสิ่งที่แชซพูดคือถ้าคุณเชื่อมั่นในการทำงานOptional(และวิธีการที่เกี่ยวข้อง) คุณไม่ต้องทดสอบอีกต่อไป ไม่ใช่ในแบบเดียวกับที่คุณทดสอบif-else: ทุกคนifเป็นเขตทุ่นระเบิดที่มีศักยภาพ Optionalและสำนวนการใช้งานที่คล้ายกันนั้นได้รับการเข้ารหัสและรับประกันว่าจะไม่เดินทางข้ามคุณดังนั้นโดยพื้นฐานแล้วจะมี "สาขา" ที่หายไป
Andres F.

1
@AndresF ฉันไม่คิดว่า Karol Optionalจะแนะนำว่าการทดสอบเรา อย่างที่เขาพูดว่ามีเหตุผลเราควรทดสอบที่getName()จัดการอินพุตที่เป็นไปได้ต่างๆในแบบที่เราต้องการโดยไม่คำนึงถึงการใช้งาน ยากที่จะตรวจสอบสิ่งนี้โดยไม่ต้องใช้เครื่องมือการครอบคลุมโค้ดเพื่อช่วยในการ pre-JDK8
Mike Partridge

1
@ MikePartridge ใช่ แต่ประเด็นก็คือไม่สามารถทำได้ผ่านการครอบคลุมสาขา จำเป็นต้องมีการครอบคลุมสาขาเมื่อเขียนif-elseเนื่องจากโครงสร้างเหล่านี้แต่ละรายการมีการโฆษณาอย่างสมบูรณ์ ในทางตรงกันข้ามOptional, orElse, mapฯลฯ ทั้งหมดที่ทดสอบแล้ว กิ่งก้านก็จะหายไปเมื่อคุณใช้สำนวนที่ทรงพลังกว่า
Andres F.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.