TL; DR
ที่ Pivotal เราเขียน Cedar เพราะเราใช้และรัก Rspec ในโครงการ Ruby ของเรา Cedar ไม่ได้หมายถึงการแทนที่หรือแข่งขันกับ OCUnit มันหมายถึงการนำความเป็นไปได้ของการทดสอบแบบ BDD มาสู่ Objective C เช่นเดียวกับ Rspec ซึ่งเป็นผู้บุกเบิกการทดสอบแบบ BDD ใน Ruby แต่ยังไม่ได้ตัด Test :: Unit การเลือกอย่างใดอย่างหนึ่งเป็นเรื่องของการกำหนดลักษณะ
ในบางกรณีเราออกแบบ Cedar เพื่อเอาชนะข้อบกพร่องบางอย่างในวิธีที่ OCUnit ทำงานให้เรา โดยเฉพาะเราต้องการให้สามารถใช้ดีบักเกอร์ในการทดสอบเพื่อรันการทดสอบจากบรรทัดคำสั่งและในการสร้าง CI และรับเอาต์พุตข้อความที่เป็นประโยชน์ของผลการทดสอบ สิ่งเหล่านี้อาจเป็นประโยชน์กับคุณไม่มากก็น้อย
คำตอบที่ยาว
การตัดสินใจระหว่างสองเฟรมเวิร์กการทดสอบเช่น Cedar และ OCUnit (ตัวอย่าง) มีสองสิ่ง: สไตล์ที่ต้องการและใช้งานง่าย ฉันจะเริ่มต้นด้วยสไตล์เพราะมันเป็นเพียงความเห็นและความชอบ ใช้งานง่ายมีแนวโน้มที่จะเป็นชุดของการแลกเปลี่ยน
การพิจารณารูปแบบที่ดีกว่าเทคโนโลยีหรือภาษาที่คุณใช้ x การทดสอบยูนิตแบบยูนิทนั้นใช้เวลานานกว่าการทดสอบสไตล์ BDD แต่ทว่าหลังนั้นได้รับความนิยมอย่างรวดเร็วเนื่องจาก Rspec
ข้อได้เปรียบหลักของการทดสอบแบบ xUnit คือความเรียบง่ายและการยอมรับอย่างกว้างขวาง (ในหมู่นักพัฒนาที่เขียนการทดสอบหน่วย) เกือบทุกภาษาที่คุณสามารถเขียนโค้ดได้มีกรอบ xUnit สไตล์พร้อมใช้งาน
เฟรมเวิร์กสไตล์ BDD มีแนวโน้มที่จะมีความแตกต่างที่สำคัญสองประการเมื่อเปรียบเทียบกับ xUnit-style: วิธีที่คุณจัดโครงสร้างการทดสอบ (หรือข้อกำหนด) และไวยากรณ์สำหรับการเขียนการยืนยันของคุณ สำหรับฉันความแตกต่างทางโครงสร้างเป็นความแตกต่างหลัก x การทดสอบหน่วยเป็นมิติเดียวด้วยวิธี setUp หนึ่งวิธีสำหรับการทดสอบทั้งหมดในคลาสทดสอบที่กำหนด อย่างไรก็ตามคลาสที่เราทดสอบไม่ใช่มิติเดียว เรามักจะต้องทดสอบการกระทำในบริบทที่แตกต่างกันที่อาจขัดแย้งกัน ตัวอย่างเช่นพิจารณาคลาส ShoppingCart อย่างง่ายพร้อมเมธอด addItem: (สำหรับจุดประสงค์ของคำตอบนี้ฉันจะใช้ Objective C ไวยากรณ์) พฤติกรรมของวิธีนี้อาจแตกต่างกันเมื่อรถเข็นว่างเปล่าเมื่อเทียบกับเมื่อรถเข็นมีรายการอื่น ๆ ; อาจแตกต่างกันหากผู้ใช้ป้อนรหัสส่วนลด มันอาจแตกต่างกันหากรายการที่ระบุสามารถ ' t ถูกส่งโดยวิธีการจัดส่งที่เลือก; ฯลฯ เนื่องจากเงื่อนไขที่เป็นไปได้เหล่านี้ตัดกันซึ่งกันและกันคุณจะพบกับบริบทที่เป็นไปได้ที่เพิ่มขึ้นในเชิงเรขาคณิต ในการทดสอบแบบ xUnit ซึ่งมักจะนำไปสู่วิธีการมากมายที่มีชื่อเช่น testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies โครงสร้างของกรอบงานสไตล์ BDD ช่วยให้คุณสามารถจัดระเบียบเงื่อนไขเหล่านี้เป็นรายบุคคลซึ่งฉันพบว่าทำให้ง่ายขึ้นเพื่อให้แน่ใจว่าฉันครอบคลุมทุกกรณีรวมทั้งง่ายต่อการค้นหาเปลี่ยนแปลงหรือเพิ่มเงื่อนไขแต่ละรายการ ตัวอย่างเช่นการใช้ไวยากรณ์ของ Cedar วิธีการด้านบนจะเป็นดังนี้: ในการทดสอบแบบ xUnit ซึ่งมักจะนำไปสู่วิธีการมากมายที่มีชื่อเช่น testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies โครงสร้างของกรอบงานสไตล์ BDD ช่วยให้คุณสามารถจัดระเบียบเงื่อนไขเหล่านี้เป็นรายบุคคลซึ่งฉันพบว่าทำให้ง่ายขึ้นเพื่อให้แน่ใจว่าฉันครอบคลุมทุกกรณีรวมทั้งง่ายต่อการค้นหาเปลี่ยนแปลงหรือเพิ่มเงื่อนไขแต่ละรายการ ตัวอย่างเช่นการใช้ไวยากรณ์ของ Cedar วิธีการด้านบนจะเป็นดังนี้: ในการทดสอบแบบ xUnit ซึ่งมักจะนำไปสู่วิธีการมากมายที่มีชื่อเช่น testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies โครงสร้างของกรอบงานสไตล์ BDD ช่วยให้คุณสามารถจัดระเบียบเงื่อนไขเหล่านี้เป็นรายบุคคลซึ่งฉันพบว่าทำให้ง่ายขึ้นเพื่อให้แน่ใจว่าฉันครอบคลุมทุกกรณีรวมทั้งง่ายต่อการค้นหาเปลี่ยนแปลงหรือเพิ่มเงื่อนไขแต่ละรายการ ตัวอย่างเช่นการใช้ไวยากรณ์ของ Cedar วิธีการด้านบนจะเป็นดังนี้:
describe(@"ShoppingCart", ^{
describe(@"addItem:", ^{
describe(@"when the cart is empty", ^{
describe(@"with no discount code", ^{
describe(@"when the shipping method applies to the item", ^{
it(@"should add the item to the cart", ^{
...
});
it(@"should add the full price of the item to the overall price", ^{
...
});
});
describe(@"when the shipping method does not apply to the item", ^{
...
});
});
describe(@"with a discount code", ^{
...
});
});
describe(@"when the cart contains other items, ^{
...
});
});
});
ในบางกรณีคุณจะพบบริบทที่มีชุดการยืนยันที่เหมือนกันซึ่งคุณสามารถ DRY โดยใช้บริบทตัวอย่างที่แชร์
ความแตกต่างหลักที่สองระหว่างเฟรมเวิร์กสไตล์ BDD และเฟรมเวิร์กสไตล์ xUnit การยืนยัน (หรือ "matcher") ไวยากรณ์ทำให้รูปแบบของสเป็คค่อนข้างดีกว่า บางคนชอบมันจริง ๆ บางคนก็ไม่ชอบ
ที่นำไปสู่คำถามของการใช้งานง่าย ในกรณีนี้แต่ละเฟรมเวิร์กมีข้อดีและข้อเสีย:
OCUnit นั้นมีความยาวมากกว่า Cedar และถูกรวมเข้ากับ Xcode โดยตรง ซึ่งหมายความว่าการสร้างเป้าหมายการทดสอบใหม่นั้นเป็นเรื่องง่ายและส่วนใหญ่แล้วจะทำการทดสอบและใช้งาน "ใช้งานได้" ในทางกลับกันเราพบว่าในบางกรณีเช่นการใช้งานบนอุปกรณ์ iOS การได้รับการทดสอบจาก OCUnit นั้นเป็นไปไม่ได้ การตั้งค่าสเปคของ Cedar นั้นใช้งานได้มากกว่าการทดสอบ OCUnit เนื่องจากคุณได้รับไลบรารี่และเชื่อมโยงกับมันด้วยตัวคุณเอง (ไม่เคยมีเรื่องเล็กน้อยใน Xcode) เรากำลังพยายามทำให้การตั้งค่าง่ายขึ้นและคำแนะนำใด ๆ ก็ยินดีต้อนรับ
OCUnit เรียกใช้การทดสอบเป็นส่วนหนึ่งของการสร้าง ซึ่งหมายความว่าคุณไม่จำเป็นต้องเรียกใช้ไฟล์ปฏิบัติการเพื่อให้การทดสอบทำงาน หากการทดสอบใด ๆ ล้มเหลวงานสร้างของคุณจะล้มเหลว สิ่งนี้ทำให้กระบวนการรันการทดสอบหนึ่งขั้นตอนง่ายขึ้นและผลลัพธ์การทดสอบจะถูกส่งไปยังหน้าต่างสร้างผลงานของคุณโดยตรงซึ่งทำให้มองเห็นได้ง่าย เราเลือกให้ Cedar specs สร้างเป็นปฏิบัติการที่คุณเรียกใช้แยกต่างหากด้วยเหตุผลสองสามประการ:
- เราต้องการที่จะใช้ดีบักเกอร์ คุณเรียกใช้ specs ของ Cedar เหมือนกับที่คุณเรียกใช้โปรแกรมอื่น ๆ ดังนั้นคุณสามารถใช้ดีบักเกอร์ได้ในลักษณะเดียวกัน
- เราต้องการการบันทึกคอนโซลอย่างง่ายในการทดสอบ คุณสามารถใช้ NSLog () ในการทดสอบ OCUnit ได้ แต่เอาต์พุตจะเข้าสู่หน้าต่างบิลด์ที่คุณต้องเปิดขั้นตอนบิลด์เพื่อที่จะอ่าน
- เราต้องการให้ง่ายต่อการอ่านรายงานการทดสอบทั้งในบรรทัดคำสั่งและใน Xcode ผลลัพธ์ของ OCUnit ปรากฏอย่างชัดเจนในหน้าต่างการสร้างใน Xcode แต่การสร้างจากบรรทัดคำสั่ง (หรือเป็นส่วนหนึ่งของกระบวนการ CI) ส่งผลให้ผลลัพธ์การทดสอบสอดแทรกด้วยเอาต์พุตบิลด์อื่น ๆ มากมาย ด้วยขั้นตอนการ build และ run แยกกัน Cedar จะแยกเอาท์พุทออกมาดังนั้นผลลัพธ์การทดสอบจึงหาง่าย ค่าเริ่มต้นของนักทดสอบซีดาร์คัดลอกสไตล์การพิมพ์มาตรฐาน "" สำหรับแต่ละสเป็คที่ผ่าน "F" สำหรับสเปคที่ล้มเหลวเป็นต้น Cedar ยังมีความสามารถในการใช้ออบเจ็กต์นักข่าวที่กำหนดเองดังนั้นคุณสามารถให้ผลลัพธ์ออกมาได้ตามที่คุณต้องการด้วยความพยายามเล็กน้อย
OCUnit เป็นกรอบการทดสอบหน่วยอย่างเป็นทางการสำหรับ Objective C และได้รับการสนับสนุนจาก Apple แอปเปิ้ลมีทรัพยากรที่ไร้ขีด จำกัด โดยทั่วไปดังนั้นหากพวกเขาต้องการบางสิ่งบางอย่างมันก็จะเสร็จ และท้ายที่สุดนี่คือ sandbox ของ Apple ที่เราเล่นอยู่อย่างไรก็ตามด้านพลิกของเหรียญนั้นคือ Apple ได้รับตามคำขอสนับสนุนมูลค่าหลายพันล้านครั้งและรายงานข้อผิดพลาดในแต่ละวัน พวกเขาดีมากเกี่ยวกับการจัดการพวกเขาทั้งหมด แต่พวกเขาอาจไม่สามารถจัดการกับปัญหาที่คุณรายงานได้ทันทีหรือเลย Cedar ใหม่กว่าและอบน้อยกว่า OCUnit มาก แต่ถ้าคุณมีคำถามหรือปัญหาหรือคำแนะนำส่งข้อความไปยังรายชื่อผู้รับจดหมายของ Cedar (cedar-discuss@googlegroups.com) และเราจะทำสิ่งที่เราสามารถช่วยคุณได้ นอกจากนี้โปรดแยกรหัสจาก Github (github.com/pivotal/cedar) และเพิ่มสิ่งที่คุณคิดว่าหายไป
การเรียกใช้การทดสอบ OCUnit บนอุปกรณ์ iOS อาจเป็นเรื่องยาก จริงๆแล้วฉันไม่ได้ลองมาซักพักนึงแล้วมันอาจจะง่ายขึ้น แต่ครั้งสุดท้ายที่ฉันลองฉันก็ไม่สามารถทดสอบ OCUnit สำหรับการทำงานของ UIKit ใด ๆ เมื่อเราเขียน Cedar เรามั่นใจว่าเราสามารถทดสอบโค้ดที่ขึ้นกับ UIKit ได้ทั้งบนโปรแกรมจำลองและบนอุปกรณ์
สุดท้ายเราเขียน Cedar สำหรับการทดสอบหน่วยซึ่งหมายความว่ามันไม่สามารถเทียบเคียงได้กับโครงการอย่าง UISpec เป็นเวลานานแล้วที่ฉันลองใช้ UISpec แต่ฉันเข้าใจว่ามันจะเน้นไปที่การขับ UI บนอุปกรณ์ iOS เป็นหลัก เราตัดสินใจเป็นพิเศษว่าจะไม่พยายามให้ Cedar รองรับคุณสมบัติเหล่านี้เนื่องจาก Apple กำลังจะประกาศ UIAutomation (ในเวลานั้น)