Mockito สามารถตั้งวิธีโดยไม่คำนึงถึงข้อโต้แย้งได้หรือไม่?


302

ฉันพยายามทดสอบรหัสดั้งเดิมโดยใช้ Mockito

ฉันต้องการ stub a FooDaoที่ใช้ในการผลิตดังนี้:

foo = fooDao.getBar(new Bazoo());

ฉันเขียนได้:

when(fooDao.getBar(new Bazoo())).thenReturn(myFoo);

แต่ปัญหาที่ชัดเจนgetBar()คือไม่เคยถูกเรียกด้วยBazooวัตถุเดียวกันกับที่ฉัน stubbed วิธีการ (สาปแช่งnewผู้ประกอบการนั้น!)

ฉันจะรักมันถ้าฉันสามารถ stub วิธีในวิธีที่มันกลับmyFooโดยไม่คำนึงถึงการโต้แย้ง ความล้มเหลวนั้นฉันจะฟังคำแนะนำการแก้ปัญหาอื่น ๆ แต่ฉันอยากจะหลีกเลี่ยงการเปลี่ยนรหัสการผลิตจนกว่าจะครอบคลุมการทดสอบที่สมเหตุสมผล

คำตอบ:


456
when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);

หรือ (เพื่อหลีกเลี่ยงnulls):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);

อย่าลืมนำเข้าเครื่องมือจับคู่ (มีอีกมากมาย):

สำหรับ Mockito 2.1.0 และใหม่กว่า:

import static org.mockito.ArgumentMatchers.*;

สำหรับรุ่นเก่า:

import static org.mockito.Matchers.*;

2
ฉันรักมันเมื่อคำตอบนำหน้าจุดจบของ 'accept answer freeze'
Eric Wilson

10
มีnotNull(Bazoo.class)เช่นเดียวกับany(Bazoo.class)(อาจจะไม่ได้อยู่ในช่วงเวลาของคำตอบนี้)
Dandre Allison

2
ฉันมีสถานการณ์พิเศษเล็กน้อยที่ฉันสามารถมีหนึ่งในสองข้อโต้แย้งที่เป็นไปได้ - BazooหรือCazooซึ่งเป็นทั้ง subclasses ของ, พูด, Azoo. สำหรับBazooฉันต้องการที่จะกลับมาfooแต่สำหรับฉันต้องการที่จะกลับมาCazoo barในสถานการณ์เช่นนี้การMatchers.any()แก้ปัญหาที่เสนอไม่สามารถทำงานได้Matchers.isA()สมบูรณ์แบบ
Tanvir

3
org.mockito.Matchersเลิกใช้แล้ว - ใช้org.mockito.ArgumentMatchersแทนคือimport static org.mockito.ArgumentMatchers.*(ดูเอกสาร )
DontDivideByZero

when(myFoo.knowsWhatsUp()).thenReturn(myMoney);
6

18

ใช้แบบนี้:

when(
  fooDao.getBar(
    Matchers.<Bazoo>any()
  )
).thenReturn(myFoo);

ก่อนที่คุณจะต้องนำเข้า Mockito.Matchers


1
นี่จะเป็นคำอธิบาย!
DrB

15

http://site.mockito.org/mockito/docs/1.10.19/org/mockito/Matchers.html

anyObject() ควรเหมาะสมกับความต้องการของคุณ

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


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

1
คลาส Matchers เลิกใช้แล้ว (ดูเอกสาร - "คลาสนี้น่าจะถูกลบในรุ่น 3.0" )
Johannes Rabauer

1

อีกทางเลือกหนึ่งคือการพึ่งพาequalsวิธีการแบบเก่าที่ดี ตราบใดที่การโต้แย้งในการwhenจำลองequalsการโต้แย้งในรหัสที่ถูกทดสอบแล้ว Mockito จะตรงกับการเยาะเย้ย

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

public class MyPojo {

    public MyPojo( String someField ) {
        this.someField = someField;
    }

    private String someField;

    @Override
    public boolean equals( Object o ) {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        MyPojo myPojo = ( MyPojo ) o;
        return someField.equals( myPojo.someField );
    }

}

จากนั้นสมมติว่าคุณรู้ว่าค่าที่ต้องการsomeFieldคืออะไรคุณสามารถเยาะเย้ยเช่นนี้

when(fooDao.getBar(new MyPojo(expectedSomeField))).thenReturn(myFoo);

ข้อดี: นี่คือชัดเจนมากขึ้นแล้วanymatchers ในฐานะผู้ตรวจทานโค้ดฉันเปิดตาไว้anyในโค้ดผู้พัฒนารุ่นใหม่เพราะมันจ้องมองตรรกะของรหัสเพื่อสร้างวัตถุที่เหมาะสมที่ถูกส่งผ่าน

con: บางครั้งสนามที่ถูกส่งผ่านไปยังวัตถุนั้นเป็นรหัสสุ่ม สำหรับกรณีนี้คุณไม่สามารถสร้างวัตถุอาร์กิวเมนต์ที่คาดไว้ในรหัสจำลองได้อย่างง่ายดาย

อีกวิธีที่เป็นไปได้คือการใช้Answerวัตถุของ Mockito ที่สามารถใช้ได้กับwhenวิธีการนั้น Answerช่วยให้คุณตัดการโทรที่เกิดขึ้นจริงและตรวจสอบอาร์กิวเมนต์อินพุตและส่งคืนวัตถุจำลอง ในตัวอย่างด้านล่างฉันใช้anyเพื่อจับการร้องขอใด ๆ กับวิธีที่ถูกเยาะเย้ย แต่ในAnswerแลมบ์ดาฉันสามารถตรวจสอบข้อโต้แย้ง Bazo เพิ่มเติม ... อาจจะตรวจสอบว่ามีการส่ง ID ที่ถูกต้องไปให้ ฉันชอบสิ่งนี้มากกว่าanyด้วยตัวเองเพื่อให้การตรวจสอบอย่างน้อยมีการโต้แย้ง

    Bar mockBar = //generate mock Bar.

    when(fooDao.getBar(any(Bazo.class))
    .thenAnswer(  ( InvocationOnMock invocationOnMock) -> {
        Bazo actualBazo = invocationOnMock.getArgument( 0 );

        //inspect the actualBazo here and thrw exception if it does not meet your testing requirements.
        return mockBar;
    } );

ดังนั้นเพื่อสรุปทั้งหมดฉันชอบอาศัยequals(ที่อาร์กิวเมนต์ที่คาดไว้และอาร์กิวเมนต์ที่แท้จริงควรจะเท่ากับแต่ละอื่น ๆ ) และถ้าไม่เท่ากับ (ไม่สามารถทำนายสถานะของอาร์กิวเมนต์ที่แท้จริง) ฉันจะ เพื่อAnswerตรวจสอบข้อโต้แย้ง

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