2012-04-25 29 views
10

Phương pháp tôi muốn thử nghiệm có một vòng lặp for với logic cho mỗi phần tử trong bList:Mockito ClassCastException

class A { 
    void someMethod(){ 

     for(B b: bList){ 
      //some logic for b 
     } 
    } 
} 

tôi nhận được một ngoại lệ khi thực hiện kiểm tra sau:

@RunWith(MockitoJUnitRunner.class) 
class ATest { 

    @Mock 
    private B b; 

    @Mock 
    private Map<Int, List<B>> bMap; 

    @Mock(answer = Answers.RETURNS_DEEP_STUBS) 
    private List<B> bList; 

    @Spy 
    @InjectMocks 
    private C c; 
    .... 

    @Test 
    public void test(){ 

     //this line executes fine 
     when(bList.size()).thenReturn(1); 

     //strangely this works fine 
     when(bMap.get(any())).thenReturn(bList); 

     //ClassCastException 
     when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b); 

     c.methodIWantToTest(); 
    } 
} 

Ngoại lệ tôi nhận được là:

java.lang.ClassCastException: 
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B

Có ai gặp phải điều này trước và đưa ra giải pháp thay thế không?

tôi đã tìm kiếm một giải pháp và đã đi qua một số liên kết: http://code.google.com/p/mockito/issues/detail?id=251http://code.google.com/p/mockito/issues/detail?id=107

+0

Đây có thể là sự cố hiện có như được chỉ ra trong các liên kết. –

+2

Bạn có thực sự cố gắng giả lập Danh sách và Bản đồ hay chỉ để minh họa vấn đề này? Tại sao bạn không chỉ sử dụng một ArrayList và HashMap thực hiện và tiêm những? – jhericks

+0

@jhericks Có bạn là chính xác, tôi nên chuyển sang sử dụng ArrayList và HashMap thực hiện. Cảm ơn –

Trả lời

18

Như this link you posted chỉ ra, bạn đã gặp phải một lỗi với Answers.RETURNS_DEEP_STUBS.

Tôi thực sự không thấy bất kỳ lý do gì để thực sự sử dụng RETURNS_DEEP_STUBS trong mã ví dụ của bạn. Bạn thực sự nên cố gắng để đánh giá xem bạn có cần sâu sơ khai, bởi vì, như là Mockito docs say, "mỗi khi một mô hình trả về một giả một nàng tiên chết." Vì vậy, nếu bạn có thể, chỉ cần lấy nó ra và ví dụ của bạn sẽ làm việc.

Tuy nhiên, nếu bạn nhấn mạnh vào việc sử dụng các lỗ sâu, bạn có thể hack xung quanh lỗi này bằng cách tăng giá trị trả về từ cuộc gọi phương thức đến Object. Ví dụ: thay thế dòng vi phạm trong mã của bạn bằng cách này:

when((Object)bList.get(0)).thenReturn(b); 

Tất cả những gì được nói, cá nhân tôi đồng ý với @jhericks. Giải pháp tốt nhất có lẽ là sử dụng ArrayList thực tế có chứa mô hình của bạn thay vì chế nhạo List. Vấn đề duy nhất là nhận danh sách của bạn được tiêm, vì vậy bạn phải sử dụng @Spy. Ví dụ:

@RunWith(MockitoJUnitRunner.class) 
class ATest{ 
    private B b = mock(B.class); 
    @Spy 
    private List<B> bList = new ArrayList<B>() {{ add(b); }}; 

    @InjectMocks 
    private C c = new C(); 

    @Test 
    public void test(){ 
    c.methodIWantToTest(); 
    // verify results 
    } 
} 
+0

Tôi đã thử cả hai lựa chọn thay thế và cả hai đều hoạt động. Tôi thấy trường hợp như đã nêu trong tài liệu Mockito và sẽ không sử dụng mocks để trả lại mocks. Cảm ơn. –

1

Thực ra tôi sẽ tìm kiếm các vấn đề về classpath và giải mã lại. Trên mockito mailing list và trackers vấn đề một số vấn đề được báo cáo có thể được theo dõi xuống classpath không chính xác (phiên bản sai của jar, vv ...) và nạp lại lớp (một số lọ đã được nạp lại, nhưng không phải mockito, sau đó dẫn đến instantiating một class với trình nạp lớp sai).

@Aces Ông có thể cho biết thêm chi tiết, giống như phiên bản và tên của công cụ bạn đang sử dụng (maven, thông số kỹ thuật, chắc chắn hơn, Play Framework, JRebel lẽ, vv ...)

+0

Tôi thay thế các mocks với ArrayList và HashMap triển khai và cũng đã cố gắng hack bằng upcasting như đề xuất trong câu trả lời. Cả hai giải pháp đều hoạt động tốt. Vì vậy, tôi không nghĩ rằng có bất kỳ vấn đề classpath trong dự án. Tôi đã có thể thực hiện các trường hợp thử nghiệm với mocks tốt cho đến bây giờ. –

0

Thật không may đây không phải là có thể

Trường hợp: kiểm tra trên API: lý do

interface ConfigurationBuilder {...} 
configurationBuilder.newServerAction("s1").withName("111")....create(); 

chính của việc sử dụng này là duy trì khả năng tương thích về thời gian biên dịch. Nhưng Mockito không thể hỗ trợ Generics trong chuỗi với RETURNS_MOCKS và các tùy chọn RETURNS_DEEP_STUBS do gõ tẩy xoá trong java:

Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1"); 
b.withName("111")...create(); 

quả trong ví dụ trên nên ServerAction nhưng trong Mockito nó là đối tượng của lớp được tạo ra.

xem Issue: Can not Return deep stubs from generic method that returns generic type #484

Các vấn đề liên quan