วัตถุประสงค์ของการจำลองวัตถุคืออะไร?


167

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


12
พวกเขาเป็นเครื่องมือสำหรับการเอาชนะสิ่งต่างๆมากมายด้วยความยืดหยุ่นที่คุณไม่ต้องการสำหรับปัญหาที่เกิดขึ้น
dsimcha

2
ความเป็นไปได้ที่ซ้ำกันของการเยาะเย้ยคืออะไร?
nawfal

คำตอบ:


361

เนื่องจากคุณบอกว่าคุณยังใหม่ต่อการทดสอบหน่วยและขอวัตถุจำลองใน "เงื่อนไขของคนธรรมดา" ฉันจะลองตัวอย่างของคนธรรมดา

การทดสอบหน่วย

ลองนึกภาพการทดสอบหน่วยสำหรับระบบนี้:

cook <- waiter <- customer

โดยทั่วไปแล้วจะง่ายต่อการมองเห็นการทดสอบส่วนประกอบระดับต่ำเช่นcook:

cook <- test driver

โปรแกรมควบคุมการทดสอบเพียงแค่สั่งอาหารที่แตกต่างกันและตรวจสอบการปรุงอาหารส่งกลับจานที่ถูกต้องสำหรับการสั่งซื้อแต่ละครั้ง

มันยากที่จะทดสอบองค์ประกอบกลางเช่นบริกรที่ใช้พฤติกรรมของส่วนประกอบอื่น ๆ เครื่องมือทดสอบที่ไร้เดียงสาอาจทดสอบองค์ประกอบของบริกรในลักษณะเดียวกับที่เราทดสอบอุปกรณ์ประกอบอาหาร

cook <- waiter <- test driver

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

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

หน่วยทดสอบวิธีการทดสอบหน่วยอิสระดังนั้นวิธีการที่ดีกว่าจะแยกองค์ประกอบภายใต้การทดสอบ (บริกร) โดยใช้สิ่งที่เป็นฟาวเลอร์เรียกคู่ทดสอบ (หุ่นต้นขั้วปลอม mocks)

    -----------------------
   |                       |
   v                       |
test cook <- waiter <- test driver

ที่นี่การทำอาหารทดสอบคือ "in cahoots" พร้อมกับโปรแกรมควบคุมการทดสอบ ระบบที่อยู่ภายใต้การทดสอบได้รับการออกแบบมาเพื่อให้ผู้ปรุงอาหารสามารถแทนที่ ( ฉีด ) เพื่อทำงานกับบริกรโดยไม่ต้องเปลี่ยนรหัสการผลิต (เช่นโดยไม่ต้องเปลี่ยนรหัสพนักงาน)

วัตถุจำลอง

ตอนนี้ตัวทดสอบการทดสอบ (ทดสอบสองครั้ง) สามารถใช้งานได้หลายวิธี:

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

ดูบทความของ Fowler สำหรับข้อมูลเฉพาะเพิ่มเติมเกี่ยวกับ fakes vs stubs vs mocks vs dummiesแต่ตอนนี้เรามามุ่งเน้นไปที่การทำอาหารจำลอง

    -----------------------
   |                       |
   v                       |
mock cook <- waiter <- test driver

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

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

การสนทนารอบ ๆ การทดสอบตามแบบจำลองอาจมีลักษณะเช่นนี้:

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

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

ไดรเวอร์ทดสอบ : ทดสอบสำเร็จแล้ว!

แต่เนื่องจากบริกรของเราเป็นของใหม่นี่คือสิ่งที่อาจเกิดขึ้น:

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

คนขับทดสอบ (วางตัวเป็นลูกค้า) ถึงพนักงานเสิร์ฟ : ฉันต้องการสุนัขร้อนโปรดให้
พนักงานเยาะเย้ยปรุงอาหาร : 1 แฮมเบอร์เกอร์โปรด
ล้อเลียนแม่ครัวหยุดทำการทดสอบ: ฉันถูกสั่งให้คาดหวังว่าจะสั่งสุนัขร้อน!

คนขับทดสอบบันทึกปัญหา: การทดสอบล้มเหลว! - บริกรเปลี่ยนคำสั่ง

หรือ

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

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

คนขับรถทดสอบบันทึกเฟรนช์ฟรายส์ที่ไม่คาดคิด: การทดสอบล้มเหลว! บริกรให้อาหารผิดจานคืน

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

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


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

8
ขอบคุณ ฉันไม่สามารถพูดได้ว่าเรากำลังทดสอบ "การนำไปใช้" โดยไม่เห็น (หรือกำหนด) สเป็คสำหรับพนักงานเสิร์ฟ คุณอาจสันนิษฐานได้ว่าพนักงานเสิร์ฟได้รับอนุญาตให้ปรุงอาหารด้วยตัวเองหรือทำตามคำสั่งตามท้องถนน แต่ฉันถือว่าข้อมูลจำเพาะสำหรับพนักงานเสิร์ฟรวมถึงการใช้พ่อครัวที่ตั้งใจ - หลังจากทั้งหมดพ่อครัวที่ผลิตเป็นพ่อครัวที่มีราคาแพงและเรา ต้องการให้บริกรของเราใช้เขา ฉันเดาว่า "ต้องสรุปว่าคุณพูดถูก - พนักงานเสิร์ฟสามารถกรอกคำสั่งได้ แต่ต้องการที่จะ" ถูกต้อง "OTOH โดยไม่มีข้อกำหนดการทดสอบไม่มีความหมาย [ต่อ ... ]
Bert F

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

1
คำตอบนี้เป็นไปตามที่ฉันไม่พอเทคนิค ฉันต้องการทราบว่าทำไมฉันจึงควรใช้วัตถุจำลองเมื่อฉันสามารถใช้วัตถุจริง
Niklas R.

1
คำอธิบายที่ดี !! ขอบคุณ!! @BertF
Bharath Murali

28

วัตถุจำลองเป็นวัตถุที่ใช้แทนวัตถุจริง ในการเขียนโปรแกรมเชิงวัตถุวัตถุจำลองเป็นวัตถุจำลองที่เลียนแบบพฤติกรรมของวัตถุจริงด้วยวิธีการควบคุม

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

http://en.wikipedia.org/wiki/Mock_object

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

คำว่า "เยาะเย้ย" บางครั้งใช้แทนกันอย่างผิดพลาดกับ "ต้นขั้ว" ความแตกต่างระหว่างคำสองคำนี้อธิบายไว้ที่นี่ โดยพื้นฐานแล้วการเยาะเย้ยเป็นวัตถุต้นขั้วที่รวมถึงความคาดหวัง (เช่น "การยืนยัน") สำหรับพฤติกรรมที่เหมาะสมของวัตถุ / วิธีการภายใต้การทดสอบ

ตัวอย่างเช่น:

class OrderInteractionTester...
  public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    Mock warehouse = mock(Warehouse.class);
    Mock mailer = mock(MailService.class);
    order.setMailer((MailService) mailer.proxy());

    mailer.expects(once()).method("send");
    warehouse.expects(once()).method("hasInventory")
      .withAnyArguments()
      .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());
  }
}

ขอให้สังเกตว่าวัตถุwarehouseและmailerจำลองจะถูกโปรแกรมด้วยผลลัพธ์ที่คาดหวัง


2
คำจำกัดความที่คุณระบุไม่แตกต่างจาก "วัตถุต้นขั้ว" อย่างน้อยที่สุดและไม่ได้อธิบายว่าวัตถุจำลองคืออะไร
Brent Arias

การแก้ไขอื่น "คำว่า 'จำลอง' บางครั้งใช้แทนกันอย่างผิดพลาดกับ 'ต้นขั้ว'"
เบรนต์เรียส

@Myst: การใช้คำทั้งสองนั้นไม่เป็นสากล มันแตกต่างกันในหมู่ผู้เขียน ฟาวเลอร์พูดอย่างนั้นและบทความ Wikipedia ก็บอกอย่างนั้น อย่างไรก็ตามอย่าลังเลที่จะแก้ไขในการเปลี่ยนแปลงและลบ downvote ของคุณ :)
Robert Harvey

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

15

วัตถุจำลองเป็นวัตถุจำลองที่เลียนแบบพฤติกรรมของวัตถุจริง โดยทั่วไปคุณเขียนวัตถุจำลองหาก:

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

12

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

โดยทั่วไปแล้วคุณจะคาดหวัง 'โปรแกรม' หรือ 'บันทึก': วิธีการโทรคุณคาดว่าชั้นของคุณจะทำกับวัตถุต้นแบบ

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

ลองคิดว่าบริการต้องทำอย่างไร: ควรได้รับ Widget จากฐานข้อมูลทำอะไรกับมันแล้วบันทึกอีกครั้ง

ดังนั้นในภาษาหลอกด้วยห้องสมุดหลอกจำลองเราจะมีสิ่งที่ชอบ:

Widget sampleWidget = new Widget();
WidgetDao mock = createMock(WidgetDao.class);
WidgetService svc = new WidgetService(mock);

// record expected calls on the dao
expect(mock.getById(id)).andReturn(sampleWidget);   
expect(mock.save(sampleWidget);

// turn the dao in replay mode
replay(mock);

svc.updateWidgetPrice(id,newPrice);

verify(mock);    // verify the expected calls were made
assertEquals(newPrice,sampleWidget.getPrice());

ด้วยวิธีนี้เราสามารถทดสอบการพัฒนาคลาสได้อย่างง่ายดายซึ่งขึ้นอยู่กับคลาสอื่น ๆ


11

ฉันขอแนะนำบทความที่ดีโดย Martin Fowlerอธิบายว่า mocks คืออะไรและแตกต่างจาก stubs อย่างไร


10
ไม่เหมาะสำหรับผู้เริ่มต้นใช่มั้ย
Robert Harvey

@ Robert ฮาร์วีย์: บางทีที่ดีอยู่แล้วจะเห็นว่ามันเป็นประโยชน์ในการทำความเข้าใจคำตอบของคุณ :)
อดัม Byrtek

บทความ Martin Fowler เขียนในลักษณะของ RFCs: แห้งและเย็น
revo

9

เมื่อหน่วยทดสอบบางส่วนของโปรแกรมคอมพิวเตอร์คุณต้องการทดสอบพฤติกรรมของส่วนนั้นโดยเฉพาะ

ตัวอย่างเช่นดูรหัสหลอกด้านล่างจากชิ้นส่วนจินตภาพของโปรแกรมที่ใช้โปรแกรมอื่นเพื่อเรียกใช้งานการพิมพ์:

If theUserIsFred then
    Call Printer(HelloFred)
Else
   Call Printer(YouAreNotFred)
End

หากคุณกำลังทดสอบสิ่งนี้คุณจะต้องการทดสอบส่วนที่ดูว่าผู้ใช้เป็น Fred หรือไม่ คุณไม่ต้องการทดสอบPrinterสิ่งต่าง ๆ นั่นจะเป็นการทดสอบอีกครั้ง

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


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

ความคาดหวังอนุญาตให้เยาะเย้ยของคุณเพื่อเพิ่มข้อผิดพลาดเมื่อมีการใช้อย่างไม่ถูกต้อง ดังนั้นในตัวอย่างข้างต้นคุณอาจต้องการให้แน่ใจว่าเครื่องพิมพ์นั้นถูกเรียกใช้ด้วย HelloFred ในกรณีทดสอบ "user is Fred" หากนั่นไม่เกิดขึ้นเยาะเย้ยของคุณสามารถเตือนคุณ

พฤติกรรมใน Mocksหมายถึงตัวอย่างเช่นรหัสของคุณทำสิ่งที่ชอบ:

If Call Printer(HelloFred) Returned SaidHello Then
    Do Something
End

ตอนนี้คุณต้องการทดสอบว่าโค้ดของคุณทำอะไรเมื่อเรียกใช้เครื่องพิมพ์และส่งคืน SaidHello ดังนั้นคุณสามารถตั้งค่า Mock เพื่อส่งคืน SaidHello เมื่อเรียกใช้ด้วย HelloFred

แหล่งข้อมูลที่ดีแห่งหนึ่งคือ Martin Fowlers โพสต์Mocks Ar ไม่ใช่ Stubs


7

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

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

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

สถานการณ์ง่าย ๆ โดยใช้ C # และ Moq:

public interface IInput {
  object Read();
}
public interface IOutput {
  void Write(object data);
}

class SUT {
  IInput input;
  IOutput output;

  public SUT (IInput input, IOutput output) {
    this.input = input;
    this.output = output;
  }

  void ReadAndWrite() { 
    var data = input.Read();
    output.Write(data);
  }
}

[TestMethod]
public void ReadAndWriteShouldWriteSameObjectAsRead() {
  //we want to verify that SUT writes to the output interface
  //input is a stub, since we don't record any expectations
  Mock<IInput> input = new Mock<IInput>();
  //output is a mock, because we want to verify some behavior on it.
  Mock<IOutput> output = new Mock<IOutput>();

  var data = new object();
  input.Setup(i=>i.Read()).Returns(data);

  var sut = new SUT(input.Object, output.Object);
  //calling verify on a mock object makes the object a mock, with respect to method being verified.
  output.Verify(o=>o.Write(data));
}

ในตัวอย่างข้างต้นฉันใช้ Moq เพื่อสาธิต stubs และ mocks Moq ใช้คลาสเดียวกันสำหรับทั้งคู่ - Mock<T>ซึ่งทำให้สับสนเล็กน้อย ไม่ว่า ณ รันไทม์การทดสอบจะล้มเหลวหากoutput.Writeไม่ได้รับการเรียกด้วยข้อมูลในparameterขณะที่ความล้มเหลวในการโทรinput.Read()จะไม่ล้มเหลว


4

เป็นคำตอบอื่นที่แนะนำผ่านลิงก์ไปยัง " Mocks Ar ไม่ใช่ Stubs " mocks เป็นรูปแบบของ "test double" เพื่อใช้แทนวัตถุจริง สิ่งที่ทำให้พวกเขาแตกต่างจากรูปแบบอื่น ๆ ของการทดสอบคู่เช่นวัตถุต้นขั้วคือการทดสอบอื่น ๆ คู่เสนอการตรวจสอบสถานะ (และการจำลองทางเลือก) ในขณะที่ mocks เสนอการตรวจสอบพฤติกรรม

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

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


3

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


1

สำหรับ php และ phunit มีการอธิบายอย่างดีในเอกสาร phpunit ดูเอกสาร phpunitที่นี่

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


0

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

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