ฉันจะใช้ TDD กับฟังก์ชั่นอ่าน / เขียนได้อย่างไร?


10

ดูเหมือนว่าปัญหาไก่และไข่

คุณสามารถทำให้เขียนฟังก์ชั่นเขียนไปยังแหล่งข้อมูลบางอย่าง แต่ไม่เคยรู้ว่าคุณบันทึกไว้อย่างถูกต้องโดยไม่ต้องฟังก์ชั่นการอ่านการทดสอบ

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

แก้ไข:

ฉันกำลังเชื่อมต่อและทำธุรกรรมกับฐานข้อมูล SQL เพื่อบันทึกและโหลดวัตถุเพื่อใช้งาน ไม่มีจุดทดสอบฟังก์ชั่นการเข้าถึงที่ DB ให้ แต่ฉันตัดฟังก์ชั่น DB ดังกล่าวเพื่อทำให้เป็นอันดับ / ดีซีเรียลไลซ์วัตถุ ฉันต้องการให้แน่ใจว่าฉันเขียนและอ่านสิ่งที่ถูกต้องไปยังและจากฐานข้อมูลอย่างถูกต้อง

มันไม่เหมือนการเพิ่ม / ลบตามที่ @snowman กล่าวถึง ฉันต้องการทราบว่าเนื้อหาที่ฉันเขียนนั้นถูกต้อง แต่ต้องใช้ฟังก์ชั่นการอ่านที่ผ่านการทดสอบเป็นอย่างดี เมื่อฉันอ่านฉันต้องการให้แน่ใจว่าการอ่านของฉันได้สร้างวัตถุอย่างถูกต้องเท่ากับสิ่งที่เขียน; แต่นั่นต้องมีฟังก์ชั่นการเขียนที่ผ่านการทดสอบเป็นอย่างดี


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


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

2
คุณสามารถจัดทำฐานข้อมูลด้วยข้อมูลและไม่มีฟังก์ชั่นการเขียนเลยเพื่อทดสอบฟังก์ชั่นการอ่าน
JeffO

คำตอบ:


7

เริ่มด้วยฟังก์ชั่นอ่าน

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

  • ในการทดสอบ : เปิดใช้งานที่เก็บของคุณชี้ไปที่การทดสอบ db ของคุณและเรียกใช้วิธีการอ่าน ตรวจสอบว่าข้อมูลการทดสอบถูกส่งคืน

ตอนนี้คุณมีฟังก์ชั่นการอ่านที่ผ่านการทดสอบอย่างสมบูรณ์แล้วคุณสามารถย้ายไปที่ฟังก์ชันเขียนซึ่งสามารถใช้การอ่านที่มีอยู่เพื่อตรวจสอบผลลัพธ์ของตัวเอง


ฉันเดาว่าคุณสามารถสร้าง DB ในหน่วยความจำเพื่อเร่งความเร็วสิ่งต่าง ๆ แต่อาจซับซ้อนเกินไป ทำไมไม่ใช้ mocks แทนในการทดสอบหน่วย?
BЈовић

1
เป็นส่วนหนึ่งของ Devil's Advocate ที่นี่ แต่คุณจะทดสอบได้อย่างไรว่าฐานข้อมูลถูกสร้างอย่างถูกต้อง? ตามที่ระบุไว้ OP ไก่และไข่
user949300

1
@Ewan - ฉันเห็นด้วยอย่างยิ่งว่าคุณไม่ควรทดสอบรหัส DB ของพวกเขา แต่คุณจะรู้ได้อย่างไรว่ารหัสการตั้งค่า DB ของคุณไม่ได้ลืม INSERT ที่ไหนสักแห่งหรือใส่ค่าผิดในคอลัมน์?
user949300

1
จากวิธีการ TDD บริสุทธิ์การทดสอบคือความต้องการ ดังนั้นมันจึงมีเหตุผลที่ผิดพลาด obvs ในโลกแห่งความจริงที่คุณต้องตามัน
Ewan

1
ผู้ดูแลระบบ ipsos custodes? หรือ "ใครเป็นคนทดสอบการทดสอบ" :-) ฉันเห็นด้วยกับคุณว่าในโลก TDD ที่พิถีพิถันนี่จะเป็นเรื่องน่าเบื่อและน่ากลัว (โดยเฉพาะถ้ามันเป็นโครงสร้างตารางที่ซับซ้อนที่มี 8 JOINS) upvoted
user949300

6

ฉันมักจะเขียนตามด้วยการอ่าน เช่น (pseudocode)

Foo foo1 = setup some object to write
File tempfile = create a tempfile, possibly in memory 
writeFoo(foo1, tempfile) 
Foo foo2 = readFoo(tempfile) 
assertEquals(foo1, foo2); 
clean-up goes here

เพิ่มในภายหลัง

นอกจากจะมีการแก้ปัญหานี้ "prgamatic" และ "ดีพอ" หนึ่งได้ยืนยันว่าการแก้ปัญหาอื่น ๆทดสอบสิ่งที่ผิด การทดสอบว่าสตริงหรือคำสั่ง SQL ที่ตรงกันนั้นไม่ใช่ความคิดที่แย่มากฉันทำเอง แต่กำลังทดสอบผลข้างเคียงและเปราะบาง ถ้าคุณเปลี่ยนการใช้อักษรตัวพิมพ์ใหญ่เพิ่มเขตข้อมูลหรืออัปเดตหมายเลขรุ่นภายในข้อมูลของคุณ จะทำอย่างไรถ้าไดรเวอร์ SQL ของคุณเปลี่ยนลำดับการเรียกเพื่อประสิทธิภาพหรือ XML serializer ที่อัปเดตของคุณจะเพิ่มพื้นที่พิเศษหรือเปลี่ยนเวอร์ชันสกีมา

ตอนนี้ถ้าคุณต้องปฏิบัติตามข้อกำหนดอย่างเป็นทางการอย่างเคร่งครัดฉันยอมรับว่าการตรวจสอบรายละเอียดที่เหมาะสมนั้นเป็นสิ่งที่เหมาะสม


1
เพราะ 90% pseudocode หนาแน่นจริง ๆ หรือ ไม่แน่ใจ. อาจเน้นข้อความและทำให้รหัสมีเสียงดังน้อยลงหรือไม่
RubberDuck

1
ใช่ @Ewan ความกระตือรือร้นจะขมวดคิ้วเมื่อสิ่งนี้อย่างไรก็ตามโปรแกรมเมอร์ในทางปฏิบัติจะพูดว่า "ดีพอ" และเดินหน้าต่อไป
RubberDuck

1
ฉันอ่านคำถามเป็น .. "สมมติว่าฉันติดตาม TDD อย่างกระตือรือร้น ... "
Ewan

1
การตีความ OP และ TDD ของฉันคือการทดสอบของคุณควรเขียนก่อนและไม่ใช้ทั้งการอ่านและการเขียนเว้นแต่จะมีการทดสอบที่อื่นเช่นกัน
Ewan

2
คุณกำลังทดสอบ 'อ่านควรส่งคืนสิ่งที่ฉันเขียน' แต่ข้อกำหนดคือ 'อ่านควรส่งคืนข้อมูลจาก db' และ 'เขียนควรเขียนข้อมูลไปยัง db'
Ewan

4

อย่า อย่าทดสอบหน่วย I / O มันเป็นการเสียเวลาเปล่า

ตรรกะการทดสอบหน่วย หากมีจำนวนมากของตรรกะที่คุณต้องการทดสอบในรหัส I / O คุณควร refactor รหัสของคุณเพื่อแยกตรรกะของวิธีที่คุณทำ I / O และสิ่ง I / O ที่คุณทำจากธุรกิจจริงของการทำ I / O (ซึ่งเป็นไปไม่ได้ที่จะทดสอบ)

หากต้องการอธิบายรายละเอียดเล็กน้อยหากคุณต้องการทดสอบเซิร์ฟเวอร์ HTTP คุณควรดำเนินการผ่านการทดสอบสองประเภท ได้แก่ การทดสอบการรวมและการทดสอบหน่วย การทดสอบหน่วยไม่ควรโต้ตอบกับ I / O เลย มันช้าและแนะนำเงื่อนไขข้อผิดพลาดมากมายที่ไม่เกี่ยวข้องกับความถูกต้องของรหัสของคุณ การทดสอบหน่วยไม่ควรขึ้นอยู่กับสถานะของเครือข่ายของคุณ!

รหัสของคุณควรแยกจากกัน:

  • ตรรกะของการพิจารณาว่าจะส่งข้อมูลใด
  • ตรรกะของการกำหนดว่าจะส่งข้อมูลไบต์ใดเพื่อส่งบิตของข้อมูลเฉพาะ (ฉันจะเข้ารหัสการตอบสนอง ฯลฯ เป็นข้อมูลดิบ) และ
  • กลไกการเขียนไบต์เหล่านั้นไปยังซ็อกเก็ต

สองคนแรกเกี่ยวข้องกับตรรกะและการตัดสินใจและต้องการการทดสอบหน่วย สุดท้ายไม่ได้เกี่ยวข้องกับการตัดสินใจมากมายหากสามารถตัดสินใจได้และสามารถทดสอบได้อย่างยอดเยี่ยมโดยใช้การทดสอบการรวม

นี่เป็นเพียงการออกแบบที่ดีโดยทั่วไปจริง ๆ แล้ว แต่หนึ่งในเหตุผลที่ทำให้การทดสอบง่ายขึ้น


นี่คือตัวอย่างบางส่วน:

  • หากคุณกำลังเขียนโค้ดที่รับข้อมูลจากฐานข้อมูลเชิงสัมพันธ์คุณสามารถทดสอบหน่วยที่จะแมปข้อมูลที่ส่งคืนจากเคียวรีเชิงสัมพันธ์กับโมเดลแอ็พพลิเคชันของคุณ
  • หากคุณกำลังเขียนโค้ดที่เขียนข้อมูลไปยังฐานข้อมูลเชิงสัมพันธ์คุณสามารถทดสอบหน่วยของข้อมูลที่คุณต้องการเขียนไปยังฐานข้อมูลโดยไม่ต้องทดสอบคิวรี่ SQL เฉพาะที่คุณใช้ ตัวอย่างเช่นคุณอาจเก็บสองสถานะแอปพลิเคชันของคุณไว้ในหน่วยความจำ: สำเนาที่แสดงว่าฐานข้อมูลมีลักษณะอย่างไรและสำเนาที่ใช้งานได้ เมื่อคุณต้องการซิงค์กับฐานข้อมูลคุณจำเป็นต้องกระจายสิ่งเหล่านี้และเขียนความแตกต่างไปยังฐานข้อมูล คุณสามารถทดสอบหน่วย diff รหัสได้ง่ายมาก
  • หากคุณกำลังเขียนโค้ดที่อ่านบางอย่างจากไฟล์กำหนดค่าคุณต้องการทดสอบ parser รูปแบบไฟล์กำหนดค่าของคุณ แต่ด้วยสตริงจากไฟล์ต้นฉบับทดสอบแทนที่จะเป็นสตริงที่คุณได้รับจากดิสก์

2

ฉันไม่ทราบว่านี่เป็นมาตรฐานการปฏิบัติหรือไม่ แต่มันก็ใช้ได้ดีสำหรับฉัน

ในการใช้งานวิธีการเขียนที่ไม่ใช่ฐานข้อมูลของฉันฉันใช้ชนิดเฉพาะของฉันเองtoString()และfromString()วิธีการเป็นรายละเอียดการใช้งาน

สิ่งเหล่านี้สามารถทดสอบแยกได้ง่าย:

 assertEquals("<xml><car type='porsche'>....", new Car("porsche").toString());

สำหรับวิธีการอ่านการเขียนจริงฉันมีหนึ่งการทดสอบการรวมที่อ่านและเขียนทางกายภาพในการทดสอบหนึ่ง

โดยวิธีการ: มีบางอย่างผิดปกติหรือไม่ที่มีหนึ่งการทดสอบที่ทดสอบอ่าน / เขียนด้วยกัน


อาจไม่รู้สึกดีหรือ "บริสุทธิ์" แต่นี่เป็นวิธีแก้ปัญหาอย่างจริงจัง
RubberDuck

ฉันก็ชอบแนวคิดของการทดสอบการอ่านและการเขียนด้วยกัน Your toString () เป็นการประนีประนอมที่ดี
user949300

1

ข้อมูลที่รู้จักจะต้องจัดรูปแบบในลักษณะที่รู้จัก วิธีที่ง่ายที่สุดในการดำเนินการนี้คือการใช้สตริงคงที่และเปรียบเทียบผลลัพธ์ตามที่ @ k3b อธิบาย

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

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


1

ใช้การฉีดพึ่งพาและการเยาะเย้ย

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

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

ในรหัสการผลิตของคุณให้ส่งวัตถุฐานข้อมูลจริง

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

วิธีนี้คุณสามารถทดสอบเลเยอร์สิ่งที่เป็นนามธรรมของเลเยอร์นามธรรมโดยไม่จำเป็นต้องมีฐานข้อมูลจริง


Advocate's Devil: คุณจะรู้ได้อย่างไรว่าคำสั่ง SQL ใดที่ "ควรได้รับ"? เกิดอะไรขึ้นถ้าไดรเวอร์ DB ปรับออเดอร์จากสิ่งที่ปรากฏในโค้ด
user949300

@ user949300 วัตถุจำลองฐานข้อมูลมักจะแทนที่ไดรเวอร์ฐานข้อมูล
Philipp

เมื่อคุณกำลังทดสอบที่เก็บไม่มีจุดฉีดไคลเอนต์ฐานข้อมูลที่เยาะเย้ย คุณต้องทดสอบว่าโค้ดของคุณรัน sql ซึ่งทำงานกับฐานข้อมูลได้หรือไม่ ไม่งั้นคุณก็แค่ทดสอบการเยาะเย้ยของคุณ
Ewan

@Ewan นั่นไม่ใช่สิ่งที่การทดสอบหน่วยเป็นเรื่องเกี่ยวกับ การทดสอบหน่วยทดสอบรหัสหนึ่งหน่วยแยกจากส่วนอื่น ๆ ของโลก คุณไม่ได้ทดสอบการโต้ตอบระหว่างส่วนประกอบเช่นรหัสของคุณและฐานข้อมูล นั่นคือสิ่งที่การทดสอบบูรณาการสำหรับ
Philipp

ใช่. ฉันว่าไม่มีหน่วยทดสอบจุดทดสอบฐานข้อมูล การทดสอบการรวมเป็นสิ่งเดียวที่ควรทำ
Ewan

0

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

NHibernate มีความคงทนข้อมูลจำเพาะทดสอบ สามารถกำหนดค่าให้ทำงานกับที่เก็บในหน่วยความจำสำหรับการทดสอบแบบรวดเร็ว

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

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