Mockito phù hợp với bất kỳ đối số lớp


153

Có cách nào để khớp với bất kỳ đối số lớp nào của thói quen mẫu bên dưới không?

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

Làm thế nào tôi có thể luôn trả về new B()bất kể lớp nào được truyền vào method? Các nỗ lực sau đây chỉ hoạt động cho trường hợp cụ thể Ađược khớp.

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

EDIT : Một giải pháp là

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

6
Class<?>kinh ngạc!
António Almeida

Giải pháp (Class <?>) Bất kỳ (Class. Class) của bạn sẽ là câu trả lời ở đây. Tôi muốn sử dụng cái đó hơn là lớp ClassOrSubgroupMatcher nhìn thấy bên dưới.
awesomeAfterSemperPhi

@superbAfterSemperPhi và johan-sjöberg Tôi đã đăng một cách khác để làm điều đó, mà không cần diễn viên. Tôi tin rằng đó có thể là một cách tốt hơn. Bạn nghĩ sao?
anmaia

Câu trả lời:


188

Hai cách khác để làm điều đó (xem nhận xét của tôi về câu trả lời trước của @Tomasz Nurkiewicz):

Cái đầu tiên dựa trên thực tế là trình biên dịch đơn giản sẽ không cho phép bạn vượt qua thứ gì đó không đúng loại:

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

Bạn mất gõ chính xác ( Class<? extends A>nhưng) nhưng nó có thể hoạt động như bạn cần.

Thứ hai là tham gia nhiều hơn nhưng được cho là một giải pháp tốt hơn nếu bạn thực sự muốn chắc chắn rằng đối số method()là một Ahoặc một lớp con của A:

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

Trường hợp ClassOrSubclassMatcherđược org.hamcrest.BaseMatcherđịnh nghĩa là:

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");
    }       
}

Phù! Tôi sẽ đi với tùy chọn đầu tiên cho đến khi bạn thực sự cần kiểm soát tốt hơn những gì method()thực sự trả về :-)


những if (obj instanceof Class)thứ gây rối cho tôi, vì vậy tôi loại bỏ nó.
Daniel Smith

Trên dòng khai báo của lớp, tôi phải đổi extends BaseMatcher<Class<T>>thành chỉ extends BaseMatcher<T>. Chỉ cần FYI, nếu bất cứ ai khác bị lỗi biên dịch, hãy thử nó.
ngày

Tôi cũng đã phải thay đổi matcheschức năng như sau:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
Jan

bất kỳ (Class. class) sẽ trả về null - làm thế nào tôi có thể tránh để trả về null
Arvind Kumar

sẽ thật tuyệt nếu thực sự thêm lớp mà tôi cần nhập vì bây giờ có rất nhiều "bất kỳ" từ mockito
jpganz18

53

Có một cách khác để làm điều đó mà không cần diễn viên:

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

Giải pháp này buộc phương thức any()trả về Class<A>kiểu và không phải giá trị mặc định của nó ( Object).


5
Matcherskhông được dùng trong các phiên bản mới hơn của Mockito và có khả năng sẽ bị xóa trong phiên bản 3.0. Sử dụng ArgumentMatchersthay thế:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
Voicu

41

Nếu bạn không biết gói nào bạn cần nhập:

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

HOẶC LÀ

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

13
Điều này đã cứu cuộc đời tôi, tôi đã vô tình nhập "bất kỳ" từ thư viện hamcrest.
Gábor Nagy

3
Bây giờ nó đã đổi thànhorg.mockito.ArgumentMatchers.any
BOWS

27

Làm thế nào về:

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

hoặc là:

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

4
Chúng sẽ biên dịch và hoạt động nếu chữ ký phương thức là method(A a)- nhưng nó (hiệu quả) method(Class<A> a)- vì vậy bạn cần sử dụng: when(a.method(isA(Class.class))).thenReturn(b);hoặcwhen(a.method((Class<A>) notNull())).thenReturn(b);
millhouse

phần thứ hai đối với tôi làm việc như sự quyến rũ. chiến đấu với bất kỳ (someClass. class) dẫn đến ngõ cụt. Nhưng (someClass. Class) notNull () đã cứu ngày của tôi
Vadim

Nếu bạn có hai phương thức có cùng tên nhưng các đối số khác nhau, bạn có thể định hướng phương thức bị chế giễu bằng phiên bản thứ hai tại đây. Phiên bản đầu tiên không cắt nó cho tôi (trên Java 8).
Patru

Cảm ơn, isA (A. class) hoạt động tốt với tôi và mvcConversionService chọn đúng lớp. Điều này đã không làm việc với bất kỳ (A. class) và eq (A. class).
d3rbastl3r

9

giải pháp từ millhouse không hoạt động nữa với phiên bản gần đây của mockito

Giải pháp này hoạt động với java 8 và mockito 2.2.9

nơi ArgumentMatcherlà một instanceoforg.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;
    }
}

Và việc sử dụng

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

điều kiện thể hiện không còn cần thiết nữa và tôi đã viết một phương pháp tiện lợi:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
Daniel Alder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.