ฉันจะเขียนการทดสอบกับบริการที่สอดคล้องกันในที่สุดได้อย่างไร


17

ฉันกำลังสร้างบริการที่อยู่ด้านบนของ Google App Engine Datastore ซึ่งเป็นที่เก็บข้อมูลที่สอดคล้องกันในที่สุด สำหรับแอปพลิเคชันของฉันนี่ใช้ได้

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

คุณจะทดสอบบริการที่สอดคล้องกันได้อย่างไรในที่สุด?


2
เหตุใดคุณจึงทดสอบว่าคาดว่าจะสามารถผลิตซ้ำกับบริการภายนอกได้ตั้งแต่แรก

... และคุณพยายามทดสอบอะไรจริง ๆ รหัสของคุณ? หรือของ Google?

5
ฉันกำลังทดสอบระบบทั้งหมด นั่นคือพวกเขากำลังทดสอบบูรณาการไม่ใช่การทดสอบหน่วย
Doug Richardson

3
How can I reproducibly test an eventually consistent service? - คุณทำไม่ได้ คุณต้องลบคำว่า "ทำซ้ำ" หรือคำว่า "ในที่สุด;" คุณมีทั้งคู่ไม่ได้
Robert Harvey

1
ในที่สุดถ้ามันสอดคล้องกันไม่ว่าจะทำซ้ำหรือไม่ผลลัพธ์ใด ๆ ก็จะประสบความสำเร็จ คุณพูดไปแล้วว่ามันดีสำหรับแอปของคุณคุณกำลังทดสอบอะไรจริง ๆ ? เหตุการณ์ที่เกิดขึ้น? การรวมกับ GAE รหัสของคุณ?
Laiv

คำตอบ:


16

พิจารณาข้อกำหนดที่ไม่ใช้งานได้เมื่อออกแบบการทดสอบการใช้งานของคุณ - ถ้าบริการของคุณมีข้อกำหนดที่ไม่ใช่หน้าที่ของ "สอดคล้องกันภายใน x (วินาที / นาที / ฯลฯ )" เพียงแค่เรียกใช้คำขอ PUT รอ x จากนั้นเรียกใช้คำขอ GET

ณ จุดนั้นถ้าข้อมูลยังไม่ 'มาถึง' คุณสามารถพิจารณาคำขอ PUT ที่จะไม่สอดคล้องกับความต้องการของคุณ


7

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

สร้างบริการปลอมที่จัดการการร้องขอ PUT และ GET แต่มีการดำเนินการเพิ่มเติมเพื่อให้สอดคล้อง การทดสอบของคุณคือ:

datastore.do_put(myobj);
datastore.make_consistent();
validate(datastore.do_get(), myobj);

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

ยังคงมีค่าการทดสอบที่โต้ตอบกับบริการจริง แต่ควรทำงานนอกเวิร์กโฟลว์การพัฒนาตามปกติเพราะจะไม่เชื่อถือได้ 100% (เช่นหากบริการไม่ทำงาน) การทดสอบเหล่านี้ควรใช้เพื่อ:

  1. ให้ตัวชี้วัดโดยเฉลี่ยและเวลากรณีที่เลวร้ายที่สุดระหว่าง PUT และ GET ที่ตามมากลายเป็นความสอดคล้อง; และ
  2. ตรวจสอบว่าบริการปลอมของคุณทำงานคล้ายกับบริการจริง ดูhttps://codewithoutrules.com/2016/07/31/verified-fakes/

6

ตกลง. "คุณกำลังทดสอบอะไร" เป็นคำถามสำคัญ

  • ฉันกำลังทดสอบตรรกะภายในของฉันว่าเกิดอะไรขึ้นหากว่าสิ่งต่างๆใน google ใช้ได้ผล

ในกรณีนี้คุณควรล้อเลียนบริการของ Google และส่งคืนการตอบกลับเสมอ

  • ฉันกำลังทดสอบตรรกะของฉันสามารถรับมือกับข้อผิดพลาดชั่วคราวที่ฉันรู้ว่า google จะผลิต

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

  • ฉันกำลังทดสอบว่าผลิตภัณฑ์ของฉันจะทำงานร่วมกับบริการ Google จริง

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


+1 สำหรับข้อเสนอแนะจำลอง - ฉันจะให้คะแนนมากขึ้นสำหรับตัวเลือกเพิ่มเติมถ้าฉันทำได้
mcottle

6

ใช้สิ่งใดสิ่งหนึ่งต่อไปนี้:

  • หลังจากใส่ให้ลอง GET N ซ้ำจนสำเร็จ ล้มเหลวหากไม่ประสบความสำเร็จหลังจาก N พยายาม
  • นอนระหว่าง PUT และ GET

น่าเสียดายที่คุณต้องเลือกค่าเวทย์มนตร์ (N หรือระยะเวลาสลีป) สำหรับทั้งสองเทคนิคนี้


1
คุณช่วยอธิบายได้ไหม: มีทางเลือกอื่นหรือไม่ ฉันคิดว่าคุณหมายถึงว่าพวกเขาเป็นทางเลือก - และนั่นคือสิ่งที่ฉันคิด แต่บางทีฉันผิด
Robin Green

1
ถูกต้องฉันหมายถึงพวกเขาเป็นทางเลือก
Doug Richardson

2

ตามที่ผมเข้าใจมันเก็บข้อมูล Google Cloud ช่วยให้ทั้งคำสั่งอย่างยิ่งที่สอดคล้องกันและสอดคล้องกันในที่สุด

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

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

ตัวอย่างเช่นคุณอาจจะมีวิธีการที่เรียกว่าและstart_debug_strong_consistency()end_debug_strong_consistency()

วิธีการเริ่มต้นจะสร้างคีย์ที่สามารถใช้เป็นคีย์บรรพบุรุษสำหรับคิวรีที่ตามมาทั้งหมดและวิธีการสิ้นสุดจะลบคีย์

การเปลี่ยนแปลงเฉพาะกับแบบสอบถามที่แท้จริงที่คุณทดสอบจะเป็นการโทรsetAncestor(your_debug_key)หากมีคีย์นั้นอยู่


1

วิธีการหนึ่งซึ่งเป็นสิ่งที่ดีในทฤษฎี แต่อาจจะไม่เสมอในทางปฏิบัติที่จะทำให้การดำเนินการเขียนทั้งหมดในระบบภายใต้การทดสอบidempotent นั่นหมายความว่าสมมติว่ารหัสทดสอบของคุณทดสอบสิ่งต่าง ๆ ตามลำดับแบบคงที่คุณสามารถลองอ่านและเขียนทั้งหมดทีละรายการจนกว่าคุณจะได้รับผลลัพธ์ตามที่คุณคาดหวังลองใหม่จนกว่าจะหมดเวลาที่กำหนดไว้ในรหัสทดสอบ นั่นคือทำสิ่งที่ A1 ลองอีกครั้งหากจำเป็นจนกว่าผลลัพธ์จะเป็น B1 จากนั้นทำสิ่งที่ A2 ลองอีกครั้งหากจำเป็นจนกว่าผลลัพธ์จะเป็น B2 เป็นต้น

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

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


1

บริการเช่น Google App Engine Datastore ขึ้นอยู่กับการจำลองข้อมูลข้ามจุดกระจาย (POP) ทั่วโลกหลายแห่ง การทดสอบการรวมกันสำหรับบริการที่สอดคล้องกันในที่สุดนั้นเป็นการทดสอบอัตราการจำลองแบบของบริการดังกล่าวในชุดของ POPs อัตราการแพร่กระจายเนื้อหาไปยัง POP ทุกครั้งในบริการที่กำหนดจะไม่เหมือนกันทุก POP ภายในบริการขึ้นอยู่กับปัจจัยหลายประการเช่นวิธีการจำลองแบบและปัญหาการขนส่งทางอินเทอร์เน็ตต่างๆ - นี่เป็นสองตัวอย่าง บัญชีใดที่รายงานส่วนใหญ่ในบริการดาต้าสโตร์ที่สอดคล้องกันในที่สุด (อย่างน้อยนั่นก็เป็นประสบการณ์ของฉันในขณะที่ฉันทำงานให้กับ CDN สำคัญ)

ในการทดสอบการจำลองแบบของวัตถุในแพลตฟอร์มที่กำหนดอย่างมีประสิทธิภาพคุณจะต้องตั้งค่าการทดสอบเพื่อขอวัตถุที่วางไว้ล่าสุดจาก POPs ของบริการแต่ละรายการโดยเฉพาะ ฉันขอแนะนำให้ทดสอบรายการ POPs หนึ่งถึงห้าครั้งหรือจนกว่า POPs ทั้งหมดในรายการ POPs ของคุณจะมีวัตถุ ต่อไปนี้เป็นชุดช่วงเวลาสำหรับทำการทดสอบที่คุณมีอิสระในการปรับ: 1, 5, 60 นาที, 12 ชั่วโมง, 25 ชั่วโมงหลังจากวางลงบนดาต้าสโตร์ กุญแจสำคัญคือการบันทึกผลลัพธ์ในแต่ละช่วงเวลาเพื่อการตรวจสอบและวิเคราะห์ในภายหลังเพื่อให้เข้าใจถึงความสามารถในการให้บริการของการทำซ้ำวัตถุทั่วโลก บ่อยครั้งที่บริการดาต้าสโตร์ดึงเฉพาะสำเนาในเครื่องไปที่ POP เมื่อมีการร้องขอในพื้นที่ [การกำหนดเส้นทางจะทำผ่านโปรโตคอล BGP ซึ่งเป็นสาเหตุที่การทดสอบของคุณต้องร้องขอวัตถุจาก POP เฉพาะแต่ละตัวเพื่อให้ใช้ได้ทั่วโลกสำหรับแพลตฟอร์มที่กำหนด] . ในกรณีของ Datastore ของ Google คุณกำลังมองหาการตั้งค่าการทดสอบของคุณเพื่อค้นหาวัตถุที่กำหนดจาก "มี 70 จุดใน 33 ประเทศ"; คุณอาจต้องรับรายการ URL ที่อยู่ POP จากฝ่ายสนับสนุนของ Google [อ้างอิง:https://cloud.google.com/about/locations/ ] หรือหาก Google ใช้ Fastly สำหรับการจำลองแบบให้การสนับสนุนอย่างรวดเร็ว [ https://www.fastly.com/resources ]

ข้อดีสองสามข้อของวิธีนี้: 1) คุณจะได้รับความรู้สึกสำหรับแพลตฟอร์มการจำลองแบบของบริการที่ได้รับรู้จุดอ่อนและจุดอ่อนโดยรวมในระดับโลก [เหมือนในระหว่างการทดสอบการรวมระบบ] 2) สำหรับวัตถุใดก็ตามที่คุณทดสอบคุณจะมีเครื่องมือสำหรับให้ความอบอุ่นกับเนื้อหา [ทำคำขอแรกที่สร้างสำเนาที่ POP ท้องถิ่นที่กำหนด] - ให้วิธีที่คุณจะมั่นใจได้ว่าเนื้อหาจะถูกเผยแพร่ไปทั่วโลกก่อนที่ลูกค้าจะร้องขอ ทุกที่ในโลก


0

ฉันมีประสบการณ์กับ Google App Engine Datastore ทำงานในท้องถิ่นแปลกใจก็มักจะ "ในที่สุด" มากกว่า "สอดคล้อง" ตัวอย่างที่ง่ายที่สุด: สร้างเอนทิตีใหม่แล้วดึงมันมา บ่อยครั้งในช่วง 5 ปีที่ผ่านมาฉันเคยเห็น SDK ที่ดำเนินการในเครื่องไม่พบเอนทิตีใหม่ทันที แต่พบหลังจากนั้นประมาณครึ่งวินาที

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

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


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