วิธีการ TDD ว่าผลลัพธ์ที่ถูกต้องจะถูกส่งกลับ


12

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

นี่คือโมดูลใหม่เพื่อผูกเข้ากับระบบที่มีอยู่ ขณะนี้การเข้าถึงข้อมูลทั้งหมดเกิดขึ้นผ่าน webservices ซึ่งส่วนใหญ่เป็นเพียงกระดาษห่อหุ้มบาง ๆ ผ่านขั้นตอนการจัดเก็บฐานข้อมูล

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

ตอนนี้ฉันไม่สามารถใส่ตรรกะนี้ลงในรหัสแอปพลิเคชันได้เนื่องจากฉันจะไม่นำเงินคืน PO นับล้านเพื่อรับโหลที่ใช้กับสามารถนำไปใช้กับร้านนี้ได้เนื่องจากข้อ จำกัด ข้างต้น

ฉันคิดว่าฉันสามารถส่งช่วงวันที่ไปยัง GetValidPOs proc และใช้ค่าเหล่านั้นเพื่อส่งคืน PO ที่ถูกต้อง แต่ถ้าเราเพิ่มข้อกำหนดอื่นให้กับสิ่งที่ถือว่าเป็น PO ที่ถูกต้อง

และฉันจะทดสอบสิ่งนี้และตรวจสอบว่ามันยังทำงานได้อย่างไร เราไม่ได้ใช้ ORM และไม่น่าจะเกิดขึ้น และฉันไม่สามารถเรียก DB ในการทดสอบของฉันได้

ผมติดอยู่.

ความคิดอื่นของฉันคือมี mocks บางตัวที่ส่งคืนข้อมูลที่ถูกต้องส่วนอื่น ๆ ที่ส่งคืนข้อมูลที่ไม่ดีและมีที่เก็บข้อมูลในตัวเครื่องเกิดข้อยกเว้นหากข้อมูลไม่ดีเกิดขึ้นและทดสอบว่าข้อผิดพลาดเกิดขึ้นหาก GetValidPOs proc ล้อเลียนที่ใช้ในการทดสอบ)

มันสมเหตุสมผลหรือไม่ หรือมีวิธีที่ดีกว่า

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


ทำไมคุณไม่เลือกเฉพาะ PO ที่ถูกต้องด้วยคำสั่ง SQL ธรรมดา? (คำถามหรือคำตอบนี้ไม่ได้หมายความถึงวิธีแก้ปัญหา)
scarfridge

คำตอบ:


7

นี่เป็นข้อเสียที่สำคัญของขั้นตอนการจัดเก็บในยุคของ TDD พวกเขามีอัพไซด์ที่แท้จริงแม้กระทั่งตอนนี้ แต่ตามคำนิยามการทดสอบใด ๆ ที่ออกกำลังกาย proc ที่เก็บไว้ไม่ใช่การทดสอบหน่วย เป็นการทดสอบการรวมที่ดีที่สุด

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

คุณยังสามารถรหัสทดสอบหน่วยที่ต้องการข้อมูลโดยสรุปสิ่งที่คุณไม่สามารถทดสอบหน่วย (คลาส ADO.NET) ลงในคลาส DAO ที่คุณสามารถเยาะเย้ย จากนั้นคุณสามารถตรวจสอบได้ว่าการโทรที่คาดหวังนั้นเกิดจากการใช้รหัสและทำให้เกิดพฤติกรรมตามความเป็นจริง (เช่นการค้นหาผลลัพธ์) ที่อนุญาตให้ทำการทดสอบกรณีการใช้งานต่างๆ อย่างไรก็ตามการตั้งค่าจริงของ SqlCommand เพื่อเรียก proc ที่จัดเก็บนั้นเป็นสิ่งสุดท้ายที่คุณสามารถทดสอบหน่วยได้โดยการตัดการสร้างคำสั่งจากการเรียกใช้คำสั่งและการเยาะเย้ยผู้ดำเนินการคำสั่ง หากสิ่งนี้ฟังดูเหมือนเป็นการแยกแยะความกังวลออกไป จำไว้ว่า "ไม่มีปัญหาที่ไม่สามารถแก้ไขได้ด้วยเลเยอร์ทางอ้อมอื่นยกเว้นการมีเลเยอร์ทางอ้อมมากเกินไป" ในบางจุดคุณต้องพูดว่า "เพียงพอฉันแค่ทดสอบหน่วยนี้ไม่ได้เรา '

ตัวเลือกอื่น:

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

  • พิจารณาอัปเกรดเป็น ORM ORM ที่มีผู้ให้บริการ Linq (เกือบทั้งหมดมีการใช้งานร่วมกัน) จะช่วยให้คุณสามารถกำหนดแบบสอบถามเป็นคำสั่ง Linq; คำสั่งนั้นสามารถมอบให้กับ Repository ที่เยาะเย้ยซึ่งมีการรวบรวมข้อมูลการทดสอบในหน่วยความจำเพื่อนำไปใช้กับมัน ดังนั้นคุณสามารถตรวจสอบแบบสอบถามได้ถูกต้องโดยไม่ต้องแตะฐานข้อมูล (คุณควรเรียกใช้แบบสอบถามในสภาพแวดล้อมการรวมเพื่อทดสอบว่าผู้ให้บริการ Linq สามารถแยกย่อยแบบสอบถามได้อย่างถูกต้อง)


2
-1 เนื่องจาก TDD! = การทดสอบหน่วย สมบูรณ์แบบที่จะรวมการทดสอบระดับการรวมเมื่อทำการ TDD
Steven A. Lowe

การทดสอบหน่วยเป็นส่วนหนึ่งของการพัฒนาที่ขับเคลื่อนการทดสอบ ในการพัฒนาแบบทดสอบที่ขับเคลื่อนคุณจะสร้างโครงกระดูกการเดินของระบบของคุณและจากนั้นเรียกใช้หน่วยการรวมและการทดสอบการทำงานในระบบนั้น การรวมหน่วยการทดสอบหรือการยอมรับของคุณล้มเหลวจากนั้นให้พวกเขาผ่านและเขียนการทดสอบเพิ่มเติม
CodeART

1
ฉันเข้าใจทุกสิ่งที่คุณทั้งคู่ ฉันพูดว่าต้องมีการทดสอบการรวมหมายความว่าคุณไม่สามารถ TDD ได้? ประเด็นของฉันคือว่าขั้นตอนการจัดเก็บไม่สามารถทดสอบแยกได้ซึ่งเป็นสิ่งที่คุณต้องการจะทำเพื่อให้ได้ codebase มากเท่าที่จะทำได้ การทดสอบ SP ต้องใช้การทดสอบการรวมที่ซับซ้อนและใช้เวลานานขึ้น ในขณะที่ยังคงดีกว่าการทดสอบด้วยตนเองชุดทดสอบที่รวมเข้าด้วยกันอาจใช้เวลาหลายชั่วโมงในการทำงานและอาจส่งผลเสียต่อความพยายามของ CI
KeithS

การทดสอบ SP มักต้องการชุดข้อมูลเฉพาะในฐานข้อมูลการทดสอบ รหัสเพื่อให้ฐานข้อมูลอยู่ในสถานะที่เหมาะสมเพื่อให้ได้ผลลัพธ์ที่คาดหวังมักจะมี LoC มากขึ้นและทำงานนานกว่าโค้ดที่คุณออกกำลังกายอยู่หลายเท่า ซึ่งจะเพิ่มความซับซ้อนของเวลาในชุดทดสอบและบ่อยครั้งที่การตั้งค่าจะต้องทำซ้ำสำหรับการทดสอบแต่ละครั้ง (และอาจจะมีหลายครั้งสำหรับ SP แต่ละอันเพื่อทดสอบว่าแต่ละฟังก์ชันตามความต้องการของแบบสอบถามภายใน)
KeithS

ขั้นตอนการจัดเก็บสามารถทดสอบแยก พวกเขาจะตรวจสอบได้อย่างไร สำหรับ Transact SQL มี tSQLt ( tsqlt.org )
kevin

4

คำแนะนำของฉันคือการแบ่งและพิชิต ลืมเกี่ยวกับฐานข้อมูลและการคงอยู่ในขณะนี้และให้ความสำคัญกับการทดสอบการใช้งานปลอมของที่เก็บหรือวัตถุการเข้าถึงข้อมูลของคุณ

ตอนนี้ฉันไม่สามารถใส่ตรรกะนี้ลงในรหัสแอปพลิเคชันได้เนื่องจากฉันจะไม่นำเงินคืน PO นับล้านเพื่อรับโหลที่ใช้กับสามารถนำไปใช้กับร้านนี้ได้เนื่องจากข้อ จำกัด ข้างต้น

ฉันจะจำลองที่เก็บที่ส่งคืนใบสั่งซื้อ สร้างแบบจำลองที่มีคำสั่งซื้อยี่สิบคี่

ฉันคิดว่าฉันสามารถส่งช่วงวันที่ไปยัง GetValidPOs proc และใช้ค่าเหล่านั้นเพื่อส่งคืน PO ที่ถูกต้อง แต่ถ้าเราเพิ่มข้อกำหนดอื่นให้กับสิ่งที่ถือว่าเป็น PO ที่ถูกต้อง

เริ่มการเรียกใช้ GetValidPOs เพื่อเรียกใช้การเยาะเย้ยแทนกระบวนการฐานข้อมูล

และฉันจะทดสอบสิ่งนี้และตรวจสอบว่ามันยังทำงานได้อย่างไร เราไม่ได้ใช้ ORM และไม่น่าจะเกิดขึ้น และฉันไม่สามารถเรียก DB ในการทดสอบของฉันได้

คุณต้องใช้การทดสอบหน่วยเพื่อให้แน่ใจว่าข้อมูลถูกส่งคืนจากการจำลอง

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

ความคิดอื่นของฉันคือมี mocks บางตัวที่ส่งคืนข้อมูลที่ถูกต้องส่วนอื่น ๆ ที่ส่งคืนข้อมูลที่ไม่ดีและมีที่เก็บข้อมูลในตัวเครื่องเกิดข้อยกเว้นหากข้อมูลไม่ดีเกิดขึ้นและทดสอบว่าข้อผิดพลาดเกิดขึ้นหาก GetValidPOs proc ล้อเลียนที่ใช้ในการทดสอบ)

ตามที่ฉันได้กล่าวไปแล้วคุณต้องมีการเยาะเย้ยที่ส่งคืนข้อมูลบางอย่างที่คุณสามารถสืบค้นได้

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


นั่นคือสิ่งที่ฉันพยายามจะทำ เพียงมีปัญหาในการเขียนการใช้งานจริงที่จะทำงานเหมือนกับการเยาะเย้ยเนื่องจากการเข้าถึงข้อมูลของเราไม่เอื้อต่อการใช้ ORM ข้อมูลส่วนใหญ่ที่ฉันต้องการอยู่ในหลายระบบและควรเข้าถึงได้ผ่านบริการบนเว็บ ... แม้ว่าจะมีการอัปเดตก็ตาม
CaffGeek

0

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

กล่าวอีกวิธีหนึ่งใช้กระบวนงานที่เก็บไว้เพื่อทดสอบกระบวนงานที่เก็บไว้เนื่องจาก:

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

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

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