วิธีจับคู่ varargs ใน Mockito อย่างถูกต้อง


152

ฉันพยายามจำลองวิธีด้วยพารามิเตอร์ vararg โดยใช้ Mockito:

interface A {
  B b(int x, int y, C... c);
}

A a = mock(A.class);
B b = mock(B.class);

when(a.b(anyInt(), anyInt(), any(C[].class))).thenReturn(b);
assertEquals(b, a.b(1, 2));

สิ่งนี้ใช้ไม่ได้อย่างไรก็ตามถ้าฉันทำสิ่งนี้แทน:

when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));

ใช้งานได้แม้ว่าฉันจะไม่ได้โต้แย้งอาร์กิวเมนต์ varargs ทั้งหมดเมื่อทำการขัดวิธี

เบาะแสใด ๆ


ความจริงที่ว่าตัวอย่างล่าสุดทำงานค่อนข้างไม่สำคัญเนื่องจากตรงกับตัวพิมพ์เมื่อพารามิเตอร์ศูนย์วาร์สผ่าน
topchef

คำตอบ:


235

Mockito 1.8.1 แนะนำตัวจับคู่ anyVararg () :

when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);

ดูประวัติของสิ่งนี้ด้วย: https://code.google.com/archive/p/mockito/issues/62

แก้ไขไวยากรณ์ใหม่หลังจากการคัดค้าน:

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);

26
anyVararg()มี Object เป็นชนิดส่งคืน ในการทำให้มันเข้ากันได้กับประเภท var arg ใด ๆ (เช่น String ... , Integer ... ฯลฯ ) ให้ทำการคัดเลือกนักแสดงอย่างชัดเจน ตัวอย่างเช่นถ้าคุณมีdoSomething(Integer number, String ... args)คุณสามารถทำรหัส / when(mock).doSomething(eq(1), (String) anyVarargs())ต้นขั้วจำลองกับสิ่งที่ต้องการ ที่ควรดูแลข้อผิดพลาดในการรวบรวม
Psycho Punch

15
สำหรับข้อมูล anyVararg เลิกใช้แล้ว: "@deprecated ตั้งแต่ 2.1.0 ใช้ any ()"
alexbt

5
Matchersเลิกใช้แล้วในขณะนี้เพื่อหลีกเลี่ยงการปะทะกันของชื่อorg.hamcrest.Matchersคลาสและมีแนวโน้มว่าจะถูกลบใน mockito v3.0 ใช้ArgumentMatchersแทน
JonyD

31

คุณลักษณะที่ไม่มีเอกสารค่อนข้างใด: หากคุณต้องการพัฒนา Matcher แบบกำหนดเองที่ตรงกับอาร์กิวเมนต์ vararg คุณต้องให้มันใช้งานorg.mockito.internal.matchers.VarargMatcherเพื่อให้ทำงานได้อย่างถูกต้อง มันเป็นอินเทอร์เฟซตัวทำเครื่องหมายว่างโดยไม่มี Mockito ที่จะเปรียบเทียบข้อโต้แย้งอย่างไม่ถูกต้องเมื่อเรียกใช้เมธอดที่มี varargs โดยใช้ Matcher ของคุณ

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

class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher {
    @Override public boolean matches(Object varargArgument) {
        return /* does it match? */ true;
    }
}

when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b);

7

คำตอบของ Eli Levine ที่นี่เป็นคำตอบทั่วไปเพิ่มเติม

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.VarargMatcher;

import static org.mockito.Matchers.argThat;

public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher {

    public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) {
        argThat(new VarArgMatcher(hamcrestMatcher));
        return null;
    }

    private final Matcher<T[]> hamcrestMatcher;

    private VarArgMatcher(Matcher<T[]> hamcrestMatcher) {
        this.hamcrestMatcher = hamcrestMatcher;
    }

    @Override
    public boolean matches(Object o) {
        return hamcrestMatcher.matches(o);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher);
    }

}

จากนั้นคุณสามารถใช้มันกับ hamerster's matchers ดังนี้

verify(a).b(VarArgMatcher.varArgThat(
            org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));

(การนำเข้าคงที่จะทำให้อ่านง่ายขึ้น)


ดี สิ่งนี้ควรสร้างไว้ใน Mockito IMO
bryant

ฉันได้ยื่นปัญหากับ Hamcrest เพื่อเพิ่มสิ่งนี้ ดูgithub.com/mockito/mockito/issues/356
ทำเครื่องหมาย

นี่สำหรับ Mockito 1 หรือไม่? ฉันได้รับข้อผิดพลาดในการรวบรวมต่าง ๆ เมื่อพยายามคอมไพล์กับ 2.10
ฟรานส์

@ ดูเหมือนว่า 2 รีลีสยังอยู่ในช่วงเบต้าเมื่อฉันเขียนคำตอบนี้ดังนั้นใช่มันอาจจะเขียนสำหรับ Mockito v1.10.19 หรือราว ๆ นั้น ( github.com/mockito/mockito/releases ) มันอาจจะอัปเดต ... :-D
Peter Westmacott

3

ฉันใช้รหัสในคำตอบของ Peter Westmacott แต่ด้วย Mockito 2.2.15 คุณสามารถทำสิ่งต่อไปนี้:

verify(a).method(100L, arg1, arg2, arg3)

ที่ไหนarg1, arg2, arg3varargs


1

สร้างคำตอบของ topchef

สำหรับ 2.0.31-beta ฉันต้องใช้ Mockito.anyVararg แทน Matchers.anyVararrg:

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);

3
สำหรับข้อมูล anyVararg เลิกใช้แล้ว: "@deprecated ตั้งแต่ 2.1.0 ใช้ any ()"
alexbt

0

ในกรณีของฉันลายเซ็นของวิธีการที่ฉันต้องการจับอาร์กิวเมนต์เป็น:

    public byte[] write(byte ... data) throws IOException;

ในกรณีนี้คุณควรส่งไปยังอาร์เรย์ไบต์อย่างชัดเจน:

       when(spi.write((byte[])anyVararg())).thenReturn(someValue);

ฉันใช้เวอร์ชั่น mockito 1.10.19


0

คุณยังสามารถวนซ้ำอาร์กิวเมนต์:

Object[] args = invocation.getArguments(); 
for( int argNo = 0; argNo < args.length; ++argNo) { 
    // ... do something with args[argNo] 
}

ตัวอย่างเช่นตรวจสอบประเภทของพวกเขาและโยนพวกเขาอย่างเหมาะสมเพิ่มลงในรายการหรืออะไรก็ตาม


0

การปรับคำตอบจาก @topchef

Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);

สำหรับเอกสาร Java สำหรับ Mockito 2.23.4, Mockito.any () "จับคู่สิ่งต่าง ๆ รวมถึงโมฆะและ varargs"


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