Mockito ตรวจสอบข้อโต้แย้งวิธี


220

ฉัน googled เกี่ยวกับเรื่องนี้ แต่ไม่พบสิ่งที่เกี่ยวข้อง ฉันมีสิ่งนี้:

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj )).thenReturn(null);

Testeable testableObj = new Testeable();
testableObj.setMockeable(mock);
command.runtestmethod();

ตอนนี้ฉันต้องการตรวจสอบว่าmymethod(Object o)สิ่งที่เรียกว่าภายในruntestmethod()ถูกเรียกด้วยวัตถุoไม่ใช่อย่างอื่น แต่ฉันมักจะผ่านการทดสอบสิ่งที่ฉันใส่ในการตรวจสอบตัวอย่างเช่นด้วย:

Mockito.verify(mock.mymethod(Mockito.eq(obj)));

หรือ

Mockito.verify(mock.mymethod(Mockito.eq(null)));

หรือ

Mockito.verify(mock.mymethod(Mockito.eq("something_else")));

ฉันผ่านการทดสอบเสมอ ฉันจะทำการยืนยันให้สำเร็จได้อย่างไร (ถ้าเป็นไปได้)

ขอบคุณ.

คำตอบ:


334

ทางเลือกที่จะมีArgumentMatcherArgumentCaptor

ตัวอย่างเป็นทางการ:

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

คุณสามารถกำหนด captor ได้โดยใช้คำอธิบายประกอบ@Captor :

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}

1
ขอบคุณสำหรับตัวอย่าง! ไม่เคยใช้มัน รู้สึกแปลก ๆ ที่มีสิ่งต่าง ๆ เช่นรหัสผู้จับกุมในโค้ด แต่มันช่วยได้
Artemis

1
ฮ่าฮ่าฉันไม่เข้าใจคำถาม แต่คำตอบช่วยฉันได้มาก ขอบคุณ :-)
Marcus K.

13
สำคัญ: Call Verify () / capture () หลังจากใช้จำลอง ฉันคิดว่ามันจะต้อง "ติดตั้ง" ก่อน ...
Daniel Alder

1
ขอบคุณสำหรับคำตอบนี้!
Jose Flavio Quispe Irrazábal

นี่เป็นคำตอบที่ยอดเยี่ยม !! ขอบคุณมาก!
Ulky Igor

61

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

import static org.mockito.Matchers.argThat

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

private class ObjectEqualityArgumentMatcher<T> extends ArgumentMatcher<T> {
    T thisObject;

    public ObjectEqualityArgumentMatcher(T thisObject) {
        this.thisObject = thisObject;
    }

    @Override
    public boolean matches(Object argument) {
        return thisObject.equals(argument);
    }
}

ตอนนี้ใช้รหัสของคุณคุณสามารถอัปเดตเป็นอ่าน ...

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj)).thenReturn(null);

Testeable obj = new Testeable();
obj.setMockeable(mock);
command.runtestmethod();

verify(mock).mymethod(argThat(new ObjectEqualityArgumentMatcher<Object>(obj)));

หากคุณเพียงแค่ไปเพื่อความเท่าเทียมกันที่แน่นอน (วัตถุเดียวกันในหน่วยความจำ) เพียงแค่ทำ

verify(mock).mymethod(obj);

วิธีนี้จะยืนยันว่าถูกเรียกครั้งเดียว


1
คุณสามารถใช้บิลด์ในReflectionEqualsชั้นเรียนเพื่อจุดประสงค์นั้น
takacsot

2
+1 สำหรับคำตอบของคุณ แต่ฉันต้องการเพิ่มที่verify(mock).mymethod(obj);ไม่ตรวจสอบความเท่าเทียมกันที่แน่นอน (วัตถุเดียวกันในหน่วยความจำ) แต่จะใช้วัตถุเท่ากับวิธีการซึ่งอาจได้รับการเขียนทับ
efux

คุณยังสามารถสร้างการใช้งานแบบไม่ระบุชื่อArgumentMatcherเพื่อให้มีรายละเอียดน้อยลง
botchniaque

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

54
  • คุณไม่จำเป็นต้องใช้eqตัวจับคู่ถ้าคุณไม่ใช้ตัวจับคู่อื่น
  • คุณไม่ได้ใช้ไวยากรณ์ที่ถูกต้อง - .verify(mock)เรียกวิธีของคุณควรจะออกไปข้างนอก ตอนนี้คุณกำลังเริ่มการตรวจสอบผลการโทรตามวิธีการโดยไม่ต้องตรวจสอบอะไรเลย (ไม่ทำการโทรวิธี) ดังนั้นการทดสอบทั้งหมดจะผ่าน

รหัสคุณควรมีลักษณะดังนี้:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");

ฉันลองก่อนและตอนนี้อีกครั้งเพื่อให้แน่ใจ ฉันยังคงมีปัญหาเดียวกันการทดสอบจะผ่านเสมอ
manolowar

2
มัน verifeis โดยการอ้างอิง
cnexans

17

argThat บวกแลมบ์ดา

นั่นคือวิธีที่คุณสามารถตรวจสอบการโต้แย้งของคุณล้มเหลว:

    verify(mock).mymethod(argThat(
      (x)->false
    ));

ที่ไหน

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

argThat บวกยืนยัน

การทดสอบดังกล่าวจะ Expected: lambda$... Was: YourClass.toSting..."พูด" คุณสามารถได้รับสาเหตุของความล้มเหลวที่เฉพาะเจาะจงมากขึ้นหากใช้การยืนยันในแลมบ์ดา:

    verify(mock).mymethod(argThat( x -> {
      assertThat(x).isNotNull();
      assertThat(x.description).contains("KEY");
      return true;
    }));

แต่: ใช้ได้เฉพาะกับ 1 วิธีเท่านั้น หากวิธีการตรวจสอบที่เรียกว่า 2+ ครั้ง mockito จะส่งผ่านชุดค่าผสมที่เรียกทั้งหมดไปยังตัวตรวจสอบแต่ละตัว ดังนั้น mockito จึงคาดว่าตัวตรวจสอบของคุณจะส่งกลับอย่างเงียบ ๆtrueสำหรับหนึ่งในชุดอาร์กิวเมนต์และfalse(ไม่มีข้อยกเว้นยืนยัน) สำหรับการโทรที่ถูกต้องอื่น ๆ ความคาดหวังนั้นไม่ใช่ปัญหาสำหรับการเรียกใช้เมธอด 1 วิธี แต่ควรคืนค่าจริง 1 ครั้ง

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

ตอนนี้การทดสอบบอกว่า: Expected: Obj.description to contain 'KEY'. Was: 'Actual description'. หมายเหตุ: ฉันใช้การassertJยืนยัน แต่ขึ้นอยู่กับคุณถึงกรอบการยืนยันที่จะใช้


argThat ด้วยข้อโต้แย้งหลาย ๆ

ถ้าคุณใช้argThat, ขัดแย้งทั้งหมดจะต้องให้กับการแข่งขัน เช่น:

    verify(mock).mymethod(eq("VALUE_1"), argThat((x)->false));
    // above is correct as eq() is also an argument matcher.

verify(mock).mymethod("VALUE_1", argThat((x)->false));

// above is incorrect; an exceptoin will be thrown, as the fist arg. is given without an argument matcher.

ที่อยู่:

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

eq จับคู่

วิธีที่ง่ายที่สุดในการตรวจสอบว่าอาร์กิวเมนต์มีค่าเท่ากันหรือไม่:

verify(mock).mymethod(eq(expectedValue));
// NOTE:   ^ where the parentheses must be closed.

อาร์กิวเมนต์โดยตรง

หากการเปรียบเทียบโดยการอ้างอิงเป็นที่ยอมรับก็ให้ดำเนินการดังนี้

verify(mock).mymethod(expectedArg);
// NOTE:   ^ where the parentheses must be closed.

สาเหตุที่verify(mock.mymethod...แท้จริงของความล้มเหลวของคำถามเดิมเป็นที่ที่ผิดของ paranthes: มันผิด ทางด้านขวาจะเป็น:verify(mock).*


1
อันนี้เป็นคำตอบที่ฉันชอบงาน & หรูหรากว่าคำตอบอื่น ๆ
Airwavezx

11

ฉันใช้ Mockito.verify ด้วยวิธีนี้

@UnitTest
public class JUnitServiceTest
{
    @Mock
    private MyCustomService myCustomService;


    @Test
    public void testVerifyMethod()
    {
       Mockito.verify(myCustomService, Mockito.never()).mymethod(parameters); // method will never call (an alternative can be pick to use times(0))
       Mockito.verify(myCustomService, Mockito.times(2)).mymethod(parameters); // method will call for 2 times
       Mockito.verify(myCustomService, Mockito.atLeastOnce()).mymethod(parameters); // method will call atleast 1 time
       Mockito.verify(myCustomService, Mockito.atLeast(2)).mymethod(parameters); // method will call atleast 2 times
       Mockito.verify(myCustomService, Mockito.atMost(3)).mymethod(parameters); // method will call at most 3 times
       Mockito.verify(myCustomService, Mockito.only()).mymethod(parameters); //   no other method called except this
    }
}

5

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


4

อีกวิธีหนึ่งคือการใช้เมธอด org.mockito.internal.matchers.Equals.Equals แทนการกำหนดใหม่:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));

3

คุณเคยลองด้วย matcher () ตัวเดียวกันหรือไม่? ในขณะที่:

verify(mockObj).someMethod(same(specificInstance));

ผมมีปัญหาเหมือนกัน. ฉันลองกับ eq () matcher เช่นเดียวกับ refEq () matcher แต่ฉันมักจะมีผลบวกปลอม เมื่อฉันใช้ matcher () เดียวกันการทดสอบล้มเหลวเมื่ออาร์กิวเมนต์มีอินสแตนซ์ต่างกันและส่งผ่านเมื่ออาร์กิวเมนต์มีอินสแตนซ์เดียวกัน


-1

คุณยังสามารถใช้ TypeSafeDiagnosingMatcher

    private Matcher<GetPackagesRequest> expectedPackageRequest(final AvailabilityRequest request) {
    return new TypeSafeDiagnosingMatcher<GetPackagesRequest>() {

        StringBuilder text = new StringBuilder(500);

        @Override
        protected boolean matchesSafely(GetPackagesRequest req, Description desc) {
            String productCode = req.getPackageIds().iterator().next().getValue();
            if (productCode.equals(request.getSupplierProductCode())) {
                text.append("ProductCode not equal! " + productCode + " , " + request.getSupplierProductCode());
                return true;
            }

            text.append(req.toString());
            return false;
        }

        @Override
        public void describeTo(Description d) {
            d.appendText(text.toString());
        }
    };
}

จากนั้นตรวจสอบการร้องขอ:

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