2012-01-27 25 views
16

Tôi đang gặp một vấn đề khi cố gắng thử một tài sản của một dịch vụ từ bên trong một thử nghiệm Junit:Mocking một tài sản của một cglib proxy dịch vụ không làm việc

@ContextConfiguration("classpath:application-config.xml") 
@RunWith(SpringJUnit4ClassRunner.class) 
public class FooServiceTests { 

    @Autowired 
    private FooServiceImpl fooService; 

    @Test 
    public void testFoo() { 
     String str = fooService.foo(); 
     assertEquals("Var", str); 
    } 

    @Before 
    public void mockFooDao() throws Exception { 
     FooDao mockFooDao = Mockito.mock(FooDao.class); 
     Mockito.when(mockFooDao.foo()).thenReturn("Var"); 
     ReflectionTestUtils.setField(fooService, "fooDao", mockFooDao); 
    } 
} 

Mocking fooDao không có hiệu lực thi hành kể từ khi kết quả không phải là mong đợi. Đây là mã của cả hai dịch vụ và dao:

@Service("fooService") 
public class FooServiceImpl implements FooService { 

    @Autowired 
    protected FooDao fooDao; 

    @Override 
    public String foo() { 
     return fooDao.foo(); 
    } 
} 

@Repository 
public class FooDaoImpl implements FooDao { 

    @Override 
    public String foo() { 
     return "foo"; 
    } 
} 

Như chúng ta có thể thấy các dịch vụ thực tế có nghĩa là để trở về "foo", nhưng các thử nghiệm chế giễu dao vì vậy dịch vụ trả về "var". Tôi biết đó là một điều CGLIB proxy liên quan nhưng tôi không thể tìm ra cách để làm cho nó hoạt động mà không cần sử dụng một setter cho tài sản fooDao. Bất kỳ trợ giúp sẽ được đánh giá cao.

Trân trọng và cảm ơn trước.

Trả lời

38

Câu trả lời ngắn

Bạn phải unwrap the proxy và thiết lập trường trên các đối tượng mục tiêu:

ReflectionTestUtils.setField(unwrapFooService(), "fooDao", mockFooDao); 

Các unwrapFooService() thể được định nghĩa như sau:

private FooServiceImpl unwrapFooService() { 
    if(AopUtils.isAopProxy(fooService) && fooService instanceof Advised) { 
     Object target = ((Advised) fooService).getTargetSource().getTarget(); 
     return (FooServiceImpl)target; 
    } 
    return null; 
} 

... một dài

Vấn đề khá phức tạp, nhưng vì vậy lvable. Như bạn đã đoán đây là một tác dụng phụ của các proxy CGLIB đang được sử dụng. Về nguyên tắc, Spring tạo một lớp con của FooServiceImpl có tên tương tự với FooServiceImpl$EnhancerByCGLIB. Phân lớp này chứa tham chiếu đến FooServiceImpl gốc cũng như ... tất cả các trường FooServiceImpl có (điều này dễ hiểu - đây là lớp con).

Do đó, thực tế có hai biến: FooServiceImpl$EnhancerByCGLIB.fooDaoFooServiceImpl.fooDao. Bạn đang chỉ định một mô hình cho dịch vụ cũ nhưng dịch vụ của bạn sử dụng sau ... I wrote về những cạm bẫy này một thời gian trước đây.

+0

Vâng! Nó đã làm việc! Cảm ơn rất nhiều Tomasz. – franDayz

+0

@ frandiaz83: vui vì tôi có thể giúp! Xem xét [chấp nhận] (http://meta.stackexchange.com/questions/5421) và/hoặc upvoting câu trả lời đúng để chỉ người đọc trong tương lai vào giải pháp thích hợp. –

+0

Vâng, tất nhiên rồi. Tôi đã chấp nhận câu trả lời nhưng tôi không thể bỏ phiếu vì tôi không có đủ danh tiếng ... Cảm ơn một lần nữa. – franDayz

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