Mockito จับคู่อาร์กิวเมนต์ของคลาสใด ๆ


153

มีวิธีจับคู่อาร์กิวเมนต์คลาสใด ๆ ของรูทีนตัวอย่างด้านล่างหรือไม่?

class A {
     public B method(Class<? extends A> a) {}
}

ฉันจะส่งคืนnew B()คลาสโดยไม่คำนึงว่าคลาสใดถูกส่งเข้ามาเสมอmethod? ความพยายามต่อไปนี้ใช้สำหรับกรณีเฉพาะที่Aตรง

A a = new A();
B b = new B();
when(a.method(eq(A.class))).thenReturn(b);

แก้ไข : ทางออกหนึ่งคือ

(Class<?>) any(Class.class)

6
Class<?>! ที่น่าตื่นตาตื่นใจ
António Almeida

โซลูชัน (Class <?>) ใด ๆ ของคุณ (Class.class) ควรเป็นคำตอบที่นี่ ฉันอยากจะใช้สิ่งนั้นมากแล้วคลาส ClassOrSubclassMatcher ที่เห็นด้านล่าง
superbAfterSemperPhi

@superbAfterSemperPhi และ johan-sjöbergฉันโพสต์อีกวิธีหนึ่งในการทำเช่นนั้นโดยไม่ต้องส่ง ฉันเชื่อว่าอาจเป็นวิธีที่ดีกว่า คุณคิดอย่างไร?
anmaia

คำตอบ:


188

อีกสองวิธีที่จะทำ (ดูความคิดเห็นของฉันในคำตอบก่อนหน้าโดย @Tomasz Nurkiewicz):

สิ่งแรกนั้นขึ้นอยู่กับความจริงที่ว่าคอมไพเลอร์ไม่ยอมให้คุณผ่านสิ่งที่ผิดประเภท:

when(a.method(any(Class.class))).thenReturn(b);

คุณสูญเสียการพิมพ์ที่แน่นอน ( Class<? extends A>) แต่อาจทำงานได้ตามที่คุณต้องการ

ประการที่สองคือมีส่วนร่วมมากขึ้น แต่เป็น arguably เป็นทางออกที่ดีกว่าถ้าคุณจริงๆต้องการให้แน่ใจว่าอาร์กิวเมนต์ที่จะmethod()เป็นAหรือ subclass ของA:

when(a.method(Matchers.argThat(new ClassOrSubclassMatcher<A>(A.class)))).thenReturn(b);

ที่ClassOrSubclassMatcherถูกorg.hamcrest.BaseMatcherกำหนดเป็น:

public class ClassOrSubclassMatcher<T> extends BaseMatcher<Class<T>> {

    private final Class<T> targetClass;

    public ClassOrSubclassMatcher(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    @SuppressWarnings("unchecked")
    public boolean matches(Object obj) {
        if (obj != null) {
            if (obj instanceof Class) {
                return targetClass.isAssignableFrom((Class<T>) obj);
            }
        }
        return false;
    }

    public void describeTo(Description desc) {
        desc.appendText("Matches a class or subclass");
    }       
}

วุ้ย ฉันจะไปกับตัวเลือกแรกจนกว่าคุณจะต้องได้รับการควบคุมที่ดีกว่าสิ่งที่method()ผลตอบแทนจริง :-)


ความif (obj instanceof Class)ยุ่งเหยิงเกิดขึ้นกับฉันดังนั้นฉันจึงลบมันออก
Daniel Smith

ในบรรทัดคำประกาศของชั้นเรียนผมต้องเปลี่ยนไปเพียงextends BaseMatcher<Class<T>> extends BaseMatcher<T>เพียงแค่ FYI หากใครก็ตามได้รับข้อผิดพลาดในการรวบรวมลองใช้ดูสิ
ม.ค.

ฉันยังต้องเปลี่ยนmatchesฟังก์ชั่นดังต่อไปนี้:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
ม.ค.

any (Class.class) ส่งคืน null - ฉันจะหลีกเลี่ยงการคืนค่า null ได้อย่างไร
Arvind Kumar

จะดีถ้าจริงเพิ่มชั้นที่ฉันต้องนำเข้าตั้งแต่ตอนนี้มี "ใด ๆ " จาก mockito จำนวนมาก
jpganz18

53

มีวิธีอื่นในการทำเช่นนั้นโดยไม่ต้องส่ง:

when(a.method(Matchers.<Class<A>>any())).thenReturn(b);

วิธีนี้จะบังคับให้วิธีany()การคืนค่าClass<A>ประเภทไม่ใช่ค่าเริ่มต้น ( Object)


5
Matchersเลิกใช้แล้วใน Mockito เวอร์ชันใหม่และมีแนวโน้มว่าจะถูกลบในเวอร์ชั่น 3.0 ใช้ArgumentMatchersแทน:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
Voicu

41

หากคุณไม่ทราบว่าคุณต้องการนำเข้าแพคเกจใด:

import static org.mockito.ArgumentMatchers.any;
any(SomeClass.class)

หรือ

import org.mockito.ArgumentMatchers;
ArgumentMatchers.any(SomeClass.class)

13
สิ่งนี้ช่วยชีวิตฉันโดยบังเอิญฉันได้นำเข้า "ใด ๆ " จากไลบรารีของ hamcrest
Gábor Nagy

3
ตอนนี้มันเปลี่ยนเป็นorg.mockito.ArgumentMatchers.any
BOWS

27

เกี่ยวกับ:

when(a.method(isA(A.class))).thenReturn(b);

หรือ:

when(a.method((A)notNull())).thenReturn(b);

4
เหล่านี้จะรวบรวมและการทำงานถ้าลายเซ็นวิธีคือmethod(A a)- แต่มันเป็น (อย่างมีประสิทธิภาพ) method(Class<A> a)- ดังนั้นคุณจะต้องใช้: when(a.method(isA(Class.class))).thenReturn(b);หรือwhen(a.method((Class<A>) notNull())).thenReturn(b);
Millhouse

ส่วนที่สองสำหรับฉันทำงานเป็นเสน่ห์ ต่อสู้กับใด ๆ (SomeClass.class) นำไปสู่การตาย แต่ (SomeClass.class) notNull () บันทึกวันของฉันไว้
Vadim

หากคุณมีสองวิธีที่มีชื่อเหมือนกัน แต่มีอาร์กิวเมนต์ที่แตกต่างกันคุณสามารถยกเลิกการกำหนดวิธีที่จะจำลองโดยใช้รุ่นที่สองได้ที่นี่ รุ่นแรกไม่ได้ตัดให้ฉัน (บน Java 8 นั่นคือ)
Patru

ขอบคุณ isA (A.class) ทำงานได้ดีสำหรับฉันและ mvcConversionService เลือกคลาสที่เหมาะสม สิ่งนี้ไม่ทำงานกับ (A.class) และ eq (A.class) ใด ๆ
d3rbastl3r

9

การแก้ปัญหาจากโรงสีไม่ทำงานอีกต่อไปกับ mockito รุ่นล่าสุด

วิธีนี้ใช้ได้กับ java 8 และ mockito 2.2.9

ArgumentMatcherเป็นตัวอย่างของที่ไหนorg.mockito.ArgumentMatcher

public class ClassOrSubclassMatcher<T> implements ArgumentMatcher<Class<T>> {

   private final Class<T> targetClass;

    public ClassOrSubclassMatcher(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    @Override
    public boolean matches(Class<T> obj) {
        if (obj != null) {
            if (obj instanceof Class) {
                return targetClass.isAssignableFrom( obj);
            }
        }
        return false;
    }
}

และการใช้งาน

when(a.method(ArgumentMatchers.argThat(new ClassOrSubclassMatcher<>(A.class)))).thenReturn(b);

เงื่อนไขของอินสแตนซ์นั้นไม่จำเป็นอีกต่อไปและฉันได้เขียนวิธีการอำนวยความสะดวก:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
Daniel Alder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.