Mockito - ความแตกต่างระหว่าง doReturn () และเมื่อ ()


198

ขณะนี้ฉันกำลังใช้ Mockito เพื่อจำลองวัตถุชั้นบริการของฉันในแอปพลิเคชัน Spring MVC ซึ่งฉันต้องการทดสอบวิธีการควบคุมของฉัน อย่างไรก็ตามในขณะที่ฉันได้รับการอ่านบนเฉพาะของ Mockito ที่ฉันได้พบว่าวิธีการที่จะเทียบเท่ากับdoReturn(...).when(...) when(...).thenReturn(...)ดังนั้นคำถามของฉันคืออะไรที่มีสองวิธีที่ทำสิ่งเดียวกันหรืออะไรคือความแตกต่างที่ลึกซึ้งระหว่างdoReturn(...).when(...)และwhen(...).thenReturn(...)?

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม


1
javadoc มีบางกรณีที่doReturn()มีประโยชน์
Sotirios Delimanolis

5
ฉันคิดว่าหนึ่งในความแตกต่างที่สำคัญคือ doReturn (... ). เมื่อ (.. ) เป็นรุ่นเก่าและไม่ปลอดภัยชนิดนั้นและด้วยเหตุนี้เราจึงสามารถใช้บางครั้งเมื่อคอมไพเลอร์บ่นเกี่ยวกับการคัดเลือก เมื่อ (.. ). ดังนั้นกลับมา (.. ) จะดีกว่ามากในแง่ของความปลอดภัยประเภท
2511882

คำตอบ:


229

ไวยากรณ์ทั้งสองสำหรับการขัดนั้นเทียบเท่ากันโดยประมาณ อย่างไรก็ตามคุณสามารถใช้สำหรับการขัดถูได้ตลอดdoReturn/whenเวลา แต่มีหลายกรณีที่คุณไม่สามารถใช้งานwhen/thenReturnได้ วิธีการขัดถือเป็นโมฆะเช่นนั้น คนอื่น ๆ รวมถึงการใช้งานกับสายลับ Mockito และขัดถูวิธีเดียวกันมากกว่าหนึ่งครั้ง

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

doReturn/whenผมขอแนะนำให้ใช้เท่านั้น ไม่มีจุดในการเรียนรู้สองไวยากรณ์เมื่อหนึ่งจะทำอะไร

คุณอาจต้องการอ้างอิงคำตอบของฉันที่Forming Mockito "grammars" - คำตอบที่ละเอียดยิ่งขึ้นสำหรับคำถามที่เกี่ยวข้องอย่างใกล้ชิด


16
ฉันไม่เห็นด้วยกับเดวิด ฉันมักจะพบกับสถานการณ์ที่ฉันกลับประเภทที่ไม่ถูกต้องเมื่อใช้งานdoReturn/whenและใช้เวลาสองสามนาทีเพื่อหาสิ่งที่ผิดพลาด when/thenReturnการตรวจสอบประเภทประเภทคอมไพล์กลายเป็นประโยชน์อย่างยิ่งกับ
Saket

11
เพียงแค่เก็บไว้ในใจว่า Mockito ขอแนะนำให้คุณใช้การใช้งานแทนwhen/thenReturn doReturn/when
CodyEngel

2
@CodyEngel และมีเหตุผลไม่มีข้อเสนอแนะดังกล่าวนอกเหนือจากสิ่งที่ผมได้อธิบายในคำตอบของฉันที่นี่และที่stackoverflow.com/q/11462697 เมื่อหลายปีก่อนฉันได้พูดคุยเรื่องนี้กับ Brice Dutheil ซึ่งกำลังทำหน้าที่เป็นผู้นำการพัฒนาของ Mockito และในความทรงจำที่ดีที่สุดของฉันเขาก็เห็นด้วย ฉันจะขอให้เขาแสดงความคิดเห็นที่นี่ (ไม่รับประกันว่าเขาจะทำ)
Dawood ibn Kareem

18
Javadocระบุว่าdoReturn/whenเป็นค้าปิด ทีมไม่แนะนำวิธีใดวิธีหนึ่ง แต่ให้สังเกตว่าwhen/thenวิธีการนั้นง่ายกว่าอ่านได้ง่ายขึ้นและมีการตรวจสอบเวลาการคอมไพล์มันเป็นวิธีการที่ทำให้ Mockito เป็นที่นิยมและใช้งานง่ายอย่าลืมว่าเมื่อมีการแชร์รหัสฐานโดย skillset ต่างๆในทีมของคุณ แต่มันมีข้อเสียเกี่ยวกับสายลับและวิธีการโมฆะ
Brice

5
สำหรับบันทึก: doReturn()มีข้อเสียอย่างใหญ่หลวงในการเปลี่ยนเป็นการเข้ารหัสสไตล์ YODA ของการเรียกใช้เมธอด สิ่งที่มาภายหลังเขียนลงก่อนคือ คนส่วนใหญ่อ่านจากซ้ายไปขวา ดังนั้นตอนนี้คุณต้องจำไว้เสมอว่าต้องย้อนกลับตรรกะกลับในหัวของคุณ
GhostCat

200

ทั้งสองวิธีมีพฤติกรรมแตกต่างกันหากคุณใช้วัตถุที่ถูกสอดแนม (ใส่คำอธิบายประกอบด้วย@Spy) แทนการเยาะเย้ย (ใส่คำอธิบายประกอบด้วย@Mock):

  • when(...) thenReturn(...) ทำให้การเรียกใช้เมธอดจริงก่อนที่ค่าที่ระบุจะถูกส่งคืน ดังนั้นหากวิธีการที่เรียกใช้มีข้อยกเว้นคุณจะต้องจัดการกับมัน / เยาะเย้ยมัน ฯลฯ แน่นอนว่าคุณยังได้รับผลลัพธ์ (สิ่งที่คุณกำหนดไว้thenReturn(...))

  • doReturn(...) when(...) ไม่ได้เรียกวิธีการเลย

ตัวอย่าง:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

ทดสอบ:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");

37
พฤติกรรมนี้ใช้ได้กับวัตถุที่สอดแนมเนื่องจากเป็น "wrapper" ของวัตถุจริง ในกรณีของวัตถุที่เยาะเย้ยมันไม่สำคัญว่าจะเป็นเมื่อ / จากนั้นกลับมาหรือ doReturn / เมื่อ วัตถุที่เยาะเย้ยไม่เคยเรียกวิธีการจริง
Rafael Orágio

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

@ Glichmut นี่เป็นสถานการณ์สมมติที่ฉันแสดงการใช้งาน / ประโยชน์ของ doReturn ในแอปพลิเคชันจริงวิธีการที่เพิ่งส่งคืนข้อยกเว้นทำให้ไม่มีเหตุผล ... แต่คุณมีวิธี (อาจจะไม่บางอย่างเช่นนี้) ซึ่งอาจโยนข้อยกเว้นในเงื่อนไขบางอย่าง ..
akcasoy

1
เพื่อความกระจ่าง: The when () .Return () - เมธอดเรียกเมธอดที่แท้จริง (ของสายลับ - ไม่สำคัญสำหรับ mocks) เพียงครั้งเดียว สิ่งนี้เกิดขึ้นในบรรทัดที่คุณระบุพฤติกรรมการเยาะเย้ย (เมื่อ ( myClass.anotherMethodInClass () .thenRet ... )) หลังจากนั้นจะไม่มีการเรียกวิธีการที่เกิดขึ้นจริงอีกครั้งอาจจะดีถ้าคุณรู้ว่าคุณคาดหวังตรรกะมัณฑนากรเมื่ออ่านคำอธิบาย ด้านบน
Jonas

ดูเหมือนว่าจะไม่ได้เปรียบdoReturn()อะไร แต่ดูเหมือนว่าห้องสมุดมีการละเมิด จุดของการสอดแนมแทนการเยาะเย้ยอย่างแท้จริงคือการใช้ประโยชน์จากการโทรที่แท้จริง พวกเขาเตือนไม่ให้ใช้สายลับเช่นนี้: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (และแนะนำให้ขยายชั้นเรียนและเอาชนะวิธีแทน)
Matthew อ่าน

13

Mockito javadoc ดูเหมือนจะบอกว่าทำไมใช้doReturn()แทนการwhen() ใช้ doReturn () ในโอกาสที่หายากเหล่านั้นเมื่อคุณไม่สามารถใช้ Mockito.when (วัตถุ)

ระวังว่า Mockito.when (Object) แนะนำให้ทำการขัดเพราะมันเป็นประเภทที่ปลอดภัยและอ่านง่าย (โดยเฉพาะอย่างยิ่งเมื่อการขัดกันโทรติดต่อ)

นี่คือโอกาสที่หายากเหล่านั้นเมื่อ doReturn () มีประโยชน์:

1.เมื่อการสอดแนมวัตถุจริงและการเรียกใช้วิธีการจริงกับสายลับจะทำให้เกิดผลข้างเคียง

List list = new LinkedList(); List spy = spy(list);

// Impossible: วิธีการจริงเรียกว่า spy.get (0) พ่น IndexOutOfBoundsException (รายการยังว่างเปล่า)

when(spy.get(0)).thenReturn("foo");

// คุณต้องใช้ doReturn () เพื่อทำการขัดถู: doReturn("foo").when(spy).get(0);

2. การเอาชนะการขัดข้อยกเว้นก่อนหน้านี้:

when(mock.foo()).thenThrow(new RuntimeException());

// Impossible: เมธอด exception-stubbed foo () ถูกเรียกดังนั้น RuntimeException จะถูกส่งออกมา when(mock.foo()).thenReturn("bar");

// คุณต้องใช้ doReturn () เพื่อทำการขัดถู:

doReturn("bar").when(mock).foo(); สถานการณ์ข้างต้นแสดงให้เห็นถึงการแลกเปลี่ยนของไวยากรณ์ที่หรูหราของ Mockito โปรดทราบว่าสถานการณ์นั้นหายากมาก การสอดแนมควรเป็นระยะ ๆ และการเอาชนะข้อยกเว้นนั้นยากมาก ไม่ต้องพูดถึงว่าโดยทั่วไปการขัดถูมากเกินไปนั้นเป็นกลิ่นที่อาจเกิดจากรหัสซึ่งชี้ให้เห็นว่าการถูมากเกินไป


7

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

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

ดังนั้นมันจะกลับเท็จเมื่อวิธีการที่เรียกว่าในกรณีทดสอบเดียวกันแล้วมันจะกลับเท็จอีกครั้งและสุดท้ายจริง


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