หน่วยทดสอบรหัสฟังก์ชั่นแบบคงที่พิมพ์


15

ฉันต้องการถามคนอื่น ๆ ว่าในกรณีนี้การทดสอบหน่วยการพิมพ์แบบสแตติกทำงานได้ดีตามที่เขียนใน haskell, scala, ocaml, nemerle, f # หรือ haXe (สุดท้ายคือสิ่งที่ฉันสนใจจริงๆ แต่ฉันต้องการ แตะเข้าไปในความรู้ของชุมชนที่ใหญ่กว่า)

ฉันถามสิ่งนี้เพราะจากความเข้าใจของฉัน:

  • ด้านหนึ่งของการทดสอบหน่วยคือการมีรายละเอียดในรูปแบบที่รันได้ อย่างไรก็ตามเมื่อใช้รูปแบบการประกาศที่แมปข้อมูลจำเพาะอย่างเป็นทางการกับความหมายของภาษาเป็นไปได้หรือไม่ที่จริงแล้วมันเป็นไปได้หรือไม่ที่จะแสดงรายละเอียดในรูปแบบที่รันได้ในวิธีที่แยกจากกัน

  • ลักษณะที่ชัดเจนของการทดสอบหน่วยคือการติดตามข้อผิดพลาดที่ไม่สามารถเปิดเผยได้ผ่านการวิเคราะห์แบบคงที่ เนื่องจากรหัสการทำงานที่ปลอดภัยประเภทนั้นเป็นเครื่องมือที่ดีในการเขียนโค้ดที่ใกล้เคียงกับที่ตัววิเคราะห์สถิตของคุณเข้าใจมากดูเหมือนว่าคุณสามารถเปลี่ยนความปลอดภัยไปสู่การวิเคราะห์แบบสถิต อย่างไรก็ตามข้อผิดพลาดง่าย ๆ เช่นการใช้xแทนy(ทั้งคู่เป็นพิกัด) ในรหัสของคุณไม่สามารถครอบคลุม ความผิดพลาดดังกล่าวอาจเกิดขึ้นในขณะที่เขียนรหัสทดสอบดังนั้นฉันไม่แน่ใจว่ามันคุ้มค่ากับความพยายามหรือไม่

  • การทดสอบหน่วยจะนำเสนอความซ้ำซ้อนซึ่งหมายความว่าเมื่อต้องการเปลี่ยนแปลงรหัสการใช้งานและการทดสอบที่ครอบคลุมรหัสนี้จะต้องเปลี่ยนทั้งคู่ แน่นอนว่าค่าโสหุ้ยนี้เป็นเรื่องเกี่ยวกับค่าคงที่ดังนั้นเราจึงสามารถโต้แย้งได้ว่ามันไม่สำคัญ ในความเป็นจริงในภาษาอย่าง Ruby นั้นไม่ได้เปรียบเทียบกับประโยชน์ที่ได้รับ แต่เนื่องจากการเขียนโปรแกรมเชิงฟังก์ชันที่ครอบคลุมการทดสอบหน่วยภาคพื้นดินจำนวนมากนั้นมีจุดประสงค์เพื่อให้ความรู้สึกว่าเป็นค่าใช้จ่ายที่คงที่เพียงอย่างเดียว

จากนี้ฉันจะอนุมานว่าการทดสอบหน่วยค่อนข้างล้าสมัยในรูปแบบการเขียนโปรแกรมนี้ แน่นอนว่าการอ้างสิทธิ์ดังกล่าวสามารถนำไปสู่สงครามศาสนาเท่านั้นดังนั้นให้ฉันตั้งคำถามนี้ง่ายๆ

เมื่อคุณใช้รูปแบบการเขียนโปรแกรมคุณใช้ขอบเขตการทดสอบแบบใดและเพราะเหตุใด (คุณหวังว่าจะได้คุณภาพสำหรับโค้ดของคุณ) หรือในทางกลับกัน: คุณมีเกณฑ์ที่คุณสามารถมีคุณสมบัติหน่วยของรหัสการทำงานแบบคงที่ตามที่ครอบคลุมโดยตัววิเคราะห์แบบคงที่และโดยไม่จำเป็นต้องครอบคลุมการทดสอบหน่วย?


4
ยังไงก็ตามถ้าคุณยังไม่ได้ลองใช้QuickCheckคุณก็ควรทำอย่างแน่นอน
Jon Purdy

scalacheck.orgเทียบเท่ากับ Scala
V-Lamp

คำตอบ:


8

ด้านหนึ่งของการทดสอบหน่วยคือการมีรายละเอียดในรูปแบบที่รันได้ อย่างไรก็ตามเมื่อใช้รูปแบบการประกาศที่แมปข้อมูลจำเพาะอย่างเป็นทางการกับความหมายภาษาเป็นไปได้หรือไม่ที่จริงแล้วมันเป็นไปได้หรือไม่ที่จะแสดงรายละเอียดในรูปแบบที่รันได้ในวิธีที่แยกจากกัน

หากคุณมีรายละเอียดที่สามารถแมปโดยตรงกับการประกาศฟังก์ชั่น - ดี แต่โดยทั่วไปแล้วสิ่งเหล่านี้คือระดับนามธรรมที่แตกต่างกันสองระดับ การทดสอบหน่วยมีจุดประสงค์เพื่อทดสอบรหัสชิ้นเดียวซึ่งเขียนเป็นแบบทดสอบกล่องสีขาวโดยนักพัฒนาซอฟต์แวร์รายเดียวกันซึ่งทำงานเกี่ยวกับฟังก์ชันนี้ รายละเอียดตามปกติดูเหมือนว่า "เมื่อฉันป้อนค่านี้ที่นี่และกดปุ่มนี้สิ่งนี้และสิ่งที่ควรจะเกิดขึ้น" โดยทั่วไปข้อมูลจำเพาะดังกล่าวนำไปสู่การทำงานและทดสอบมากกว่าหนึ่งฟังก์ชัน

อย่างไรก็ตามข้อผิดพลาดง่าย ๆ เช่นการใช้ x แทน y (ทั้งคู่เป็นพิกัด) ในรหัสของคุณไม่สามารถครอบคลุมได้ อย่างไรก็ตามข้อผิดพลาดดังกล่าวอาจเกิดขึ้นในขณะที่เขียนรหัสทดสอบดังนั้นฉันไม่แน่ใจว่ามันคุ้มค่ากับความพยายามหรือไม่

ความเข้าใจผิดของคุณอยู่ที่นี่ที่การทดสอบหน่วยเป็นจริงสำหรับการค้นหาข้อบกพร่องในรหัสของคุณมือแรก - ที่ไม่เป็นความจริงอย่างน้อยก็เป็นจริงเพียงบางส่วนเท่านั้น พวกเขาถูกสร้างขึ้นเพื่อป้องกันคุณจากการแนะนำข้อบกพร่องในภายหลังเมื่อรหัสของคุณวิวัฒนาการ ดังนั้นเมื่อคุณทดสอบฟังก์ชั่นของคุณเป็นครั้งแรกและการทดสอบหน่วยของคุณทำงาน (โดยมี "x" และ "y" อยู่ในตำแหน่งที่เหมาะสม) จากนั้นในขณะที่ refactor คุณใช้ x แทน y ดังนั้นการทดสอบหน่วยจะแสดงให้คุณเห็น

การทดสอบหน่วยจะนำเสนอความซ้ำซ้อนซึ่งหมายความว่าเมื่อต้องการเปลี่ยนแปลงรหัสการใช้งานและการทดสอบที่ครอบคลุมรหัสนี้จะต้องเปลี่ยนทั้งคู่ แน่นอนว่าค่าโสหุ้ยนี้เป็นเรื่องเกี่ยวกับค่าคงที่ดังนั้นเราจึงสามารถโต้แย้งได้ว่ามันไม่สำคัญ ในความเป็นจริงในภาษาอย่าง Ruby นั้นไม่ได้เปรียบเทียบกับประโยชน์ที่ได้รับ แต่เนื่องจากการเขียนโปรแกรมเชิงฟังก์ชันที่ครอบคลุมการทดสอบหน่วยภาคพื้นดินจำนวนมากนั้นมีจุดประสงค์เพื่อให้ความรู้สึกว่าเป็นค่าใช้จ่ายที่คงที่เพียงอย่างเดียว

ในด้านวิศวกรรมระบบความปลอดภัยส่วนใหญ่พึ่งพาความซ้ำซ้อน ตัวอย่างเช่นการหยุดรถสองครั้งการกระโดดร่มซ้ำซ้อนสำหรับนักกระโดดน้ำบนท้องฟ้า ฯลฯ แนวคิดเดียวกันนี้ใช้กับการทดสอบหน่วย แน่นอนว่าการมีรหัสมากกว่านี้เพื่อเปลี่ยนเมื่อการเปลี่ยนแปลงข้อกำหนดอาจเป็นข้อเสีย ดังนั้นโดยเฉพาะอย่างยิ่งในการทดสอบหน่วยสิ่งสำคัญคือการทำให้พวกเขาแห้ง (ตามหลักการ "อย่าทำซ้ำตัวเอง" หลักการ) ในภาษาที่พิมพ์แบบคงที่คุณอาจต้องเขียนการทดสอบหน่วยน้อยกว่าในภาษาที่พิมพ์อย่างอ่อน โดยเฉพาะอย่างยิ่งการทดสอบ "ทางการ" อาจไม่จำเป็น - ซึ่งเป็นสิ่งที่ดีเพราะมันทำให้คุณมีเวลามากขึ้นในการทดสอบหน่วยที่สำคัญซึ่งทดสอบสิ่งที่สำคัญ และอย่าคิดว่าเพียงเพราะคุณเป็นประเภทคงที่คุณไม่จำเป็นต้องทำการทดสอบหน่วยยังมีพื้นที่เหลือเฟือที่จะแนะนำข้อบกพร่องในขณะที่ทำการปรับโครงสร้างใหม่


5

ด้านหนึ่งของการทดสอบหน่วยคือการมีรายละเอียดในรูปแบบที่รันได้ อย่างไรก็ตามเมื่อใช้รูปแบบการประกาศที่แมปข้อมูลจำเพาะอย่างเป็นทางการกับความหมายภาษาเป็นไปได้หรือไม่ที่จริงแล้วมันเป็นไปได้หรือไม่ที่จะแสดงรายละเอียดในรูปแบบที่รันได้ในวิธีที่แยกจากกัน

เป็นไปได้ยากมากที่คุณจะสามารถแสดงข้อมูลจำเพาะของคุณอย่างสมบูรณ์ว่าเป็นข้อ จำกัด ประเภท

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

ในความเป็นจริงประโยชน์สำคัญอย่างหนึ่งของรูปแบบนี้คือฟังก์ชั่นที่บริสุทธิ์นั้นง่ายต่อการทดสอบหน่วย: ไม่จำเป็นต้องตั้งค่าสถานะภายนอกหรือตรวจสอบหลังจากดำเนินการ

บ่อยครั้งที่ข้อมูลจำเพาะ (หรือส่วนหนึ่งของมัน) ของฟังก์ชั่นสามารถแสดงเป็นคุณสมบัติที่เกี่ยวข้องกับค่าที่ส่งกลับไปยังข้อโต้แย้ง ในกรณีนี้การใช้QuickCheck (สำหรับ Haskell) หรือScalaCheck (สำหรับ Scala) สามารถช่วยให้คุณเขียนคุณสมบัติเหล่านี้เป็นนิพจน์ของภาษาและตรวจสอบว่าพวกเขามีการป้อนข้อมูลแบบสุ่ม


1
รายละเอียดเพิ่มเติมเล็กน้อยเกี่ยวกับ QuickCheck: แนวคิดพื้นฐานคือคุณเขียน "คุณสมบัติ" (ค่าคงที่ในโค้ดของคุณ) และระบุวิธีสร้างอินพุตที่เป็นไปได้ Quickcheck จะสร้างอินพุตสุ่มจำนวนมากและตรวจสอบให้แน่ใจว่าค่าคงที่ของคุณมีค่าในทุกกรณี มันละเอียดกว่าการทดสอบหน่วย
Tikhon Jelvis

1

คุณสามารถนึกถึงการทดสอบหน่วยเป็นตัวอย่างของวิธีใช้รหัสพร้อมคำอธิบายว่าทำไมจึงมีค่า

นี่คือตัวอย่างที่ลุงบ๊อบเป็นชนิดพอที่จะคู่กับฉันในจอห์นคอนเวย์ "เกมแห่งชีวิต" ฉันคิดว่ามันเป็นการออกกำลังกายที่ยอดเยี่ยมสำหรับสิ่งนี้ การทดสอบส่วนใหญ่นั้นเป็นแบบเต็มระบบทดสอบทั้งเกม แต่การทดสอบครั้งแรกเป็นการทดสอบเพียงหนึ่งฟังก์ชั่นซึ่งเป็นการคำนวณเพื่อนบ้านที่อยู่รอบ ๆ เซลล์ คุณจะเห็นว่าการทดสอบทั้งหมดเขียนขึ้นในรูปแบบการประกาศพร้อมกับพฤติกรรมที่เรากำลังมองหาสะกดอย่างชัดเจน

มันเป็นไปได้ที่จะเลียนแบบฟังก์ชั่นที่ใช้ในฟังก์ชั่น; อย่างใดอย่างหนึ่งโดยผ่านพวกเขาเข้าไปในฟังก์ชั่น (เทียบเท่าฉีดพึ่งพา) หรือมีกรอบเช่นไบรอันมาริกของ Midje


0

ใช่หน่วยทดสอบมีความรู้สึกแล้วกับโค้ดฟังก์ชันที่พิมพ์แบบคงที่ ตัวอย่างง่ายๆ:

prop_encode a = (decode . encode $ a) == a

คุณสามารถบังคับprop_encodeกับประเภทคงที่

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