Tiêm Mockito giả vào đậu mùa xuân


284

Tôi muốn tiêm một đối tượng giả Mockito vào một bean Spring (3+) cho mục đích thử nghiệm đơn vị với JUnit. Phụ thuộc đậu của tôi hiện đang được tiêm bằng cách sử dụng @Autowiredchú thích trên các trường thành viên tư nhân.

Tôi đã xem xét việc sử dụng ReflectionTestUtils.setFieldnhưng ví dụ bean mà tôi muốn tiêm thực sự là một proxy và do đó không khai báo các trường thành viên riêng của lớp đích. Tôi không muốn tạo một trình thiết lập công khai thành phần phụ thuộc vì sau đó tôi sẽ sửa đổi giao diện của mình hoàn toàn cho mục đích thử nghiệm.

Tôi đã làm theo một số lời khuyên được đưa ra bởi cộng đồng Spring nhưng bản giả không được tạo và hệ thống tự động không thành công:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.package.Dao" />
</bean>

Lỗi tôi hiện đang gặp phải như sau:

...
Caused by: org...NoSuchBeanDefinitionException:
    No matching bean of type [com.package.Dao] found for dependency:
    expected at least 1 bean which qualifies as autowire candidate for this dependency.
    Dependency annotations: {
        @org...Autowired(required=true),
        @org...Qualifier(value=dao)
    }
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)

Nếu tôi đặt constructor-arggiá trị thành một cái gì đó không hợp lệ, không có lỗi xảy ra khi bắt đầu bối cảnh ứng dụng.


4
Xin hãy xem sinh vật nhỏ bé này: bitbucket.org/kubek2k/springockito/wiki/Home
kubek2k

Đây là một cách tiếp cận rất sạch sẽ - tôi thích nó!
teabot

2
Bạn đã cho tôi tại Springockito-chú thích.
yihtserns


2
Đối với những người sử dụng mùa xuân 4. *, kể từ tháng 1 năm 2015, điều này dường như không hoạt động với phiên bản mockito mùa xuân mới nhất và dự án dường như không hoạt động.
Murali

Câu trả lời:


130

Cách tốt nhất là:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.package.Dao" /> 
</bean> 

Cập nhật
Trong tệp ngữ cảnh, bản giả này phải được liệt kê trước bất kỳ trường tự động nào tùy thuộc vào nó được khai báo.


Tôi gặp lỗi: "Lỗi khi tạo bean với tên 'mockito': định nghĩa bean là trừu tượng"
tttppp

4
@amra: spring dos không suy ra loại đối tượng được trả về trong trường hợp này ... stackoverflow.com/q/6976421/306488
lisak

7
Không biết tại sao câu trả lời này được nâng cấp quá nhiều, kết quả có thể không được tự động vì nó có loại sai.
azerole

4
Nó có thể được tự động nếu nó được liệt kê đầu tiên trong tệp ngữ cảnh (trước khi bất kỳ trường tự động nào phụ thuộc vào nó được khai báo.)
Ryan Walls

3
Kể từ mùa xuân 3.2, thứ tự của đậu không còn quan trọng nữa. Xem phần có tiêu đề "Phương pháp nhà máy chung" trong bài đăng trên blog này: spring.io/blog/2012/11/07/iêu
Tường Ryan

110
@InjectMocks
private MyTestObject testObject;

@Mock
private MyDependentObject mockedObject;

@Before
public void setup() {
        MockitoAnnotations.initMocks(this);
}

Điều này sẽ tiêm bất kỳ đối tượng giả nào vào lớp thử nghiệm. Trong trường hợp này, nó sẽ tiêm mockedObject vào testObject. Điều này đã được đề cập ở trên nhưng đây là mã.


1
Làm thế nào để tôi sơ khai một phương pháp cụ thể mockedObject?
Jim Holden

@Teinacher khi (mockedObject.execute) .thenReturn (objToReturn); Bạn có thể đặt nó trong phương thức trước hoặc bên trong phương thức thử nghiệm của bạn.
chaostheory

40
FYI: Cách tiếp cận này sẽ không hiệu quả, nếu tôi muốn Autowires một phần và chế giễu một phần trong MyTestObject.
raksja

9
Tôi không biết tại sao điều này không được bình chọn cao hơn. Nếu tôi thấy bất kỳ câu trả lời nào có chứa XML, tôi sẽ nhanh chân.
MarkOfHall

3
Tại sao bạn không sử dụng Mockito.spy(...)mockedObjectđể thay thế? Và sau đó sử dụng when(mockedObject.execute).thenReturn(objToReturn)hoặc doReturn(objToReturn).when(mockedObject).execute(). Thứ hai không gọi phương thức thực. Bạn cũng có thể kiểm tra Mockito.doCallRealMethod()tài liệu
Tomasz Przybylski 10/03/2016

63

Tôi có một giải pháp rất đơn giản khi sử dụng Spring Java Config và Mockito:

@Configuration
public class TestConfig {

    @Mock BeanA beanA;
    @Mock BeanB beanB;

    public TestConfig() {
        MockitoAnnotations.initMocks(this); //This is a key
    }

    //You basically generate getters and add @Bean annotation everywhere
    @Bean
    public BeanA getBeanA() {
        return beanA;
    }

    @Bean
    public BeanB getBeanB() {
        return beanB;
    }
}

4
Vì một số lý do với cách tiếp cận này, mùa xuân cố gắng tạo ra bean thực sự (thay vì giả) và bóp nghẹt điều đó ... Tôi đang làm gì sai?
Daniel Gruszchot

1
Tôi có cùng một vấn đề
Korobko Alex 7/8/2015

3
Không phải mùa xuân mà là mockito cố gắng khởi tạo một bean thực sự nếu bạn đang chế nhạo một lớp. Nếu bạn có bất kỳ hạt đậu nào phải bị chế giễu trong các thử nghiệm, chúng nên được triển khai một giao diện và được tiêm qua giao diện đó. Nếu sau đó bạn giả định giao diện (chứ không phải lớp), mockito sẽ không cố gắng khởi tạo lớp đó.
Daniel Gruszchot

7
Điểm là gì? Tại sao thêm các trường chú thích và hàm tạo với initMocks? Tại sao không chỉ return Mockito.mock(BeanA.class)trong getBeanA? Cách này đơn giản hơn và có ít mã hơn. Tôi đang thiếu gì?
Oleg

1
@ Có vẻ như bạn có giải pháp của riêng mình, có lẽ bạn nên đăng bài dưới dạng câu trả lời, để cộng đồng có thể bình chọn.
Dawood ibn Kareem

48

Được:

@Service
public class MyService {
    @Autowired
    private MyDAO myDAO;

    // etc
}

Bạn có thể có lớp đang được kiểm tra được tải thông qua tự động, giả định sự phụ thuộc với Mockito, sau đó sử dụng ReflectionTestUtils của Spring để đưa giả vào lớp đang được kiểm tra.

@ContextConfiguration(classes = { MvcConfiguration.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
    @Autowired
    private MyService myService;

    private MyDAO myDAOMock;

    @Before
    public void before() {
        myDAOMock = Mockito.mock(MyDAO.class);
        ReflectionTestUtils.setField(myService, "myDAO", myDAOMock);
    }

    // etc
}

Xin lưu ý rằng trước Mùa xuân 4.3.1, phương pháp này sẽ không hoạt động với các dịch vụ đằng sau một proxy ( ví dụ, được chú thích bằng @Transactional, hoặc Cacheable, chẳng hạn). Điều này đã được sửa chữa bởi XUÂN-14050 .

Đối với các phiên bản trước, một giải pháp là mở khóa proxy, như được mô tả ở đó: Chú thích giao dịch tránh các dịch vụ bị chế giễu (đó là ReflectionTestUtils.setFieldmặc định hiện tại)


Double @RunWith (SpringJUnit4ClassRunner. Class) và tôi sử dụng các chú thích khác nhau cho lớp kiểm tra (cùng một người chạy) nhưng cách tiếp cận này hiệu quả với tôi, cảm ơn.
dùng1317422

1
Tôi đã được truyền cảm hứng rất nhiều bởi "Xin lưu ý rằng trước Mùa xuân 4.3.1, phương pháp này sẽ không hoạt động với các dịch vụ đằng sau một proxy (ví dụ như được chú thích bằng @Transactional hoặc Bộ nhớ cache). Điều này đã được sửa bởi XUÂN-14050". Tôi chỉ gặp vấn đề này một cách chính xác và không nhận được manh mối nào cho đến khi phát hiện ra những từ này. CẢM ƠN RẤT NHIỀU!
snowfox

1
Giải pháp này xử lý khi bạn kết nối toàn bộ bối cảnh ứng dụng và, với mục đích thử nghiệm, muốn đưa một giả vào một bean ngẫu nhiên trong ngữ cảnh của bạn. Tôi đã sử dụng câu trả lời này để giả lập một bean khách giả để tránh các lệnh gọi REST đến các mô-đun khác trong thử nghiệm Mô-đun. Tôi chỉ có chú thích MethMock hoạt động khi bạn đang tiêm giả trong một bean mà bạn sắp kiểm tra, không phải trong một bean được tạo bởi Cấu hình ứng dụng Spring.
Andreas Lundgren

1
Gần một ngày trôi qua, cố gắng để @MockBean hoạt động mà không đặt lại bối cảnh và sau đó tôi bắt gặp viên ngọc này. Chính xác những gì tôi cần, chúc mừng.
Matt R

Hoạt động, mặc dù hãy cẩn thận rằng trường được thay thế có thể không được đặt lại do bộ đệm và một số thử nghiệm không liên quan có thể bị hỏng. Ví dụ, trong thử nghiệm của tôi, tôi đã thay thế bộ mã hóa mật khẩu bằng một giả và một vài thử nghiệm khác bị hỏng do lỗi ủy quyền.
alextsil

36

Nếu bạn đang sử dụng Spring Boot 1.4, nó có một cách tuyệt vời để làm điều này. Chỉ cần sử dụng thương hiệu mới @SpringBootTesttrên lớp của bạn và @MockBeantrên sân và Spring Boot sẽ tạo ra một bản mô phỏng loại này và nó sẽ đưa nó vào bối cảnh (thay vì tiêm bản gốc):

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

    @MockBean
    private RemoteService remoteService;

    @Autowired
    private Reverser reverser;

    @Test
    public void exampleTest() {
        // RemoteService has been injected into the reverser bean
        given(this.remoteService.someCall()).willReturn("mock");
        String reverse = reverser.reverseSomeCall();
        assertThat(reverse).isEqualTo("kcom");
    }

}

Mặt khác, nếu bạn không sử dụng Spring Boot hoặc bạn đang sử dụng phiên bản trước, bạn sẽ phải thực hiện thêm một chút công việc:

Tạo một @Configurationbean đưa mock của bạn vào bối cảnh Spring:

@Configuration
@Profile("useMocks")
public class MockConfigurer {

    @Bean
    @Primary
    public MyBean myBeanSpy() {
        return mock(MyBean.class);
    }
}

Sử dụng @Primarychú thích bạn đang nói với mùa xuân rằng loại đậu này được ưu tiên nếu không có vòng loại được chỉ định.

Hãy chắc chắn rằng bạn chú thích lớp với @Profile("useMocks")để kiểm soát lớp nào sẽ sử dụng giả và lớp nào sẽ sử dụng bean thực.

Cuối cùng, trong thử nghiệm của bạn, kích hoạt userMockshồ sơ:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
@ActiveProfiles(profiles={"useMocks"})
public class YourIntegrationTestIT {

    @Inject
    private MyBean myBean; //It will be the mock!


    @Test
    public void test() {
        ....
    }
}

Nếu bạn không muốn sử dụng giả nhưng đậu thực sự, chỉ cần không kích hoạt useMockshồ sơ:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
public class AnotherIntegrationTestIT {

    @Inject
    private MyBean myBean; //It will be the real implementation!


    @Test
    public void test() {
        ....
    }
}

5
Câu trả lời này nên được đặt lên hàng đầu - hỗ trợ @MockBean trong boot mùa xuân cũng có thể được sử dụng mà không cần spring-boot. Bạn chỉ có thể sử dụng nó trong các bài kiểm tra đơn vị để nó hoạt động cho tất cả các ứng dụng mùa xuân!
bedrin

2
Chú thích @Profile bạn cũng có thể đặt phương thức định nghĩa bean, để tránh tạo lớp cấu hình riêng biệt
marcin

Câu trả lời chính xác! Tôi đã thực hiện một vài thay đổi để làm cho nó hoạt động với web.xmlthiết lập AnnotationConfigWebApplicationContext cũ của tôi . Phải sử dụng @WebAppConfigurationthay vì @WebIntegrationTest@ContextHierarchyvới @ContextConfigurationthay vì @SpringApplicationConfiguration.
UTF_or_Death 28/07/17

Tôi đã phải thêm @Primarychú thích cho trường hợp của mình, vì có một cuộc gọi thất bại bên trong @PostConstructmà tôi muốn chế giễu, nhưng @PostConstructhạt đậu được tạo ra trước giả của tôi để nó không sử dụng giả (cho đến khi tôi thêm @Primary).
helleye

19

1.8.3 Mockito có @InjectMocks- điều này cực kỳ hữu ích. Kiểm tra JUnit của tôi là @RunWithsự MockitoJUnitRunnervà tôi xây dựng @Mockcác đối tượng đáp ứng tất cả các phụ thuộc cho lớp đang được thử nghiệm, tất cả được tiêm khi các thành viên tư nhân được chú thích với @InjectMocks.

Tôi @RunWithchỉ SpringJUnit4Runnercho các bài kiểm tra tích hợp.

Tôi sẽ lưu ý rằng nó dường như không thể tiêm List<T>theo cách tương tự như Spring. Nó chỉ tìm kiếm một đối tượng Mock thỏa mãn Listvà sẽ không đưa vào danh sách các đối tượng Mock. Cách giải quyết đối với tôi là sử dụng một @Spydanh sách được khởi tạo thủ công và thủ công. Thêm các đối tượng giả vào danh sách đó để kiểm tra đơn vị. Có lẽ đó là cố ý, bởi vì nó chắc chắn buộc tôi phải chú ý đến những gì đang bị chế giễu cùng nhau.


Vâng, đây là cách tốt nhất. Springockito không thực sự tiêm giả cho bất kỳ lý do gì trong trường hợp của tôi.
chaostheory

13

Cập nhật: Hiện nay có giải pháp tốt hơn, sạch hơn cho vấn đề này. Hãy xem xét các câu trả lời khác đầu tiên.

Cuối cùng tôi đã tìm thấy một câu trả lời cho điều này bằng cách ronen trên blog của mình. Vấn đề tôi gặp phải là do phương thức Mockito.mock(Class c)khai báo kiểu trả về Object. Do đó, Spring không thể suy ra loại đậu từ loại trả về của phương thức nhà máy.

Giải pháp của Ronen là tạo ra một FactoryBeantriển khai trả về giả. Các FactoryBeangiao diện cho phép xuân để truy vấn các loại của các đối tượng được tạo ra bởi đậu nhà máy.

Định nghĩa đậu giả của tôi bây giờ trông giống như:

<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
    <property name="type" value="com.package.Dao" />
</bean>

1
Liên kết được cập nhật tới Giải pháp của Ronen: narkisr.com/blog/2008/2647754885089732945
Jeff Martin

Tôi không hiểu rằng, phương thức xuất xưởng có loại trả về Object ... Nhưng giải pháp của amra có kiểu trả về chung để Spring nhận ra nó ... Nhưng giải pháp của amra không hiệu quả với tôi
lisak

Không phải là giải pháp này, mùa xuân không suy ra loại đậu được trả về từ nhà máy. Do đó, không có loại đậu nào phù hợp với loại [com.package.Dao] ...
lisak


Liên kết này thực sự vẫn hoạt động: javadevelopmentforthemasses.blogspot.com/2008/07/NH Chỉ cần vô hiệu hóa chuyển hướng liên kết trong trình duyệt của bạn và bạn sẽ thấy nó, thay vì buộc phải xem 404 trên blog mới của mình.
approxiblue

12

Kể từ Mùa xuân 3.2, đây không còn là vấn đề nữa. Spring hiện hỗ trợ Tự động kết quả của các phương pháp chung của nhà máy. Xem phần có tiêu đề "Phương pháp nhà máy chung" trong bài đăng trên blog này: http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/ .

Điểm mấu chốt là:

Trong Spring 3.2, các kiểu trả về chung cho các phương thức xuất xưởng hiện đã được suy luận chính xác và việc tự động theo loại cho các mô phỏng sẽ hoạt động như mong đợi. Do đó, các công việc tùy chỉnh như MockitoFactoryBean, EasyMockFactoryBean hoặc Springockito dường như không còn cần thiết nữa.

Điều đó có nghĩa là điều này sẽ làm việc ra khỏi hộp:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.package.Dao" />
</bean>

9

Mã bên dưới hoạt động với chế độ tự động - nó không phải là phiên bản ngắn nhất nhưng hữu ích khi nó chỉ hoạt động với các lọ lò xo / mockito tiêu chuẩn.

<bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="target"> <bean class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.package.Dao" /> </bean> </property>
   <property name="proxyInterfaces"> <value>com.package.Dao</value> </property>
</bean> 

Đã làm cho tôi. Tôi đã phải mở khóa proxy trong thử nghiệm của mình để xác minh nó như được mô tả ở đây: forum.spring.io/forum/spring-projects/aop/ Lỗi
Holgzn

9

Nếu bạn đang sử dụng spring> = 3.0 , hãy thử sử dụng @Configurationchú thích Springs để xác định một phần bối cảnh ứng dụng

@Configuration
@ImportResource("com/blah/blurk/rest-of-config.xml")
public class DaoTestConfiguration {

    @Bean
    public ApplicationService applicationService() {
        return mock(ApplicationService.class);
    }

}

Nếu bạn không muốn sử dụng @ImportResource, bạn cũng có thể thực hiện theo cách khác:

<beans>
    <!-- rest of your config -->

    <!-- the container recognize this as a Configuration and adds it's beans 
         to the container -->
    <bean class="com.package.DaoTestConfiguration"/>
</beans>

Để biết thêm thông tin, hãy xem tham khảo spring-framework: Cấu hình bộ chứa dựa trên Java


Đẹp một. Tôi đã sử dụng điều này khi thử nghiệm mà tôi đang thử nghiệm là @Autowired trong trường hợp thử nghiệm thực tế.
enkor

8

Có lẽ không phải là giải pháp hoàn hảo, nhưng tôi có xu hướng không sử dụng lò xo để làm DI cho các bài kiểm tra đơn vị. các phụ thuộc cho một bean duy nhất (lớp đang thử) thường không quá phức tạp nên tôi chỉ thực hiện tiêm trực tiếp vào mã kiểm tra.


3
Tôi hiểu cách tiếp cận của bạn. Tuy nhiên, tôi thấy mình trong tình huống này trên một cơ sở mã di sản lớn không dễ dàng cho phép điều này - chưa.
teabot

1
Tôi đã tìm thấy kết hợp Mockito / Spring rất hữu ích khi tôi cần kiểm tra mã phụ thuộc nhiều vào các khía cạnh của Spring / AOP (ví dụ: khi kiểm tra các quy tắc bảo mật mùa xuân). Mặc dù người ta hoàn toàn có lý khi tuyên bố rằng các thử nghiệm như vậy nên là một thử nghiệm tích hợp.
Lars Tackmann

@Lars - đã đồng ý - điều tương tự có thể được nói về các bài kiểm tra tôi đang xử lý.
teabot

7

Tôi có thể thực hiện các thao tác sau bằng Mockito:

<bean id="stateMachine" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.abcd.StateMachine"/>
</bean>

1
Cảm ơn câu trả lời @Alexander. Tôi có thể hỏi: nó có nối dây đúng không? Nếu vậy bạn đang sử dụng phiên bản nào của Spring / Mockito?
teabot

6

Đăng một vài ví dụ dựa trên các phương pháp trên

Với mùa xuân:

@ContextConfiguration(locations = { "classpath:context.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class TestServiceTest {
    @InjectMocks
    private TestService testService;
    @Mock
    private TestService2 testService2;
}

Không có mùa xuân:

@RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {
    @InjectMocks
    private TestService testService = new TestServiceImpl();
    @Mock
    private TestService2 testService2;
}

2

Cập nhật - câu trả lời mới tại đây: https://stackoverflow.com/a/19454282/411229 . Câu trả lời này chỉ áp dụng cho những người trên phiên bản Spring trước 3.2.

Tôi đã tìm kiếm một giải pháp dứt khoát hơn cho vấn đề này. Bài đăng trên blog này dường như đáp ứng tất cả các nhu cầu của tôi và không dựa vào thứ tự khai báo đậu. Tất cả tín dụng cho Mattias Severson. http://www.jayway.com/2011/11/30/spring-integration-tests-part-i-creating-mock-objects/

Về cơ bản, triển khai FactoryBean

package com.jayway.springmock;

import org.mockito.Mockito;
import org.springframework.beans.factory.FactoryBean;

/**
 * A {@link FactoryBean} for creating mocked beans based on Mockito so that they 
 * can be {@link @Autowired} into Spring test configurations.
 *
 * @author Mattias Severson, Jayway
 *
 * @see FactoryBean
 * @see org.mockito.Mockito
 */
public class MockitoFactoryBean<T> implements FactoryBean<T> {

    private Class<T> classToBeMocked;

    /**
     * Creates a Mockito mock instance of the provided class.
     * @param classToBeMocked The class to be mocked.
     */
    public MockitoFactoryBean(Class<T> classToBeMocked) {
        this.classToBeMocked = classToBeMocked;
    }

    @Override
    public T getObject() throws Exception {
        return Mockito.mock(classToBeMocked);
    }

    @Override
    public Class<?> getObjectType() {
        return classToBeMocked;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

Tiếp theo cập nhật cấu hình mùa xuân của bạn với các mục sau:

<beans...>
    <context:component-scan base-package="com.jayway.example"/>

    <bean id="someDependencyMock" class="com.jayway.springmock.MockitoFactoryBean">
        <constructor-arg name="classToBeMocked" value="com.jayway.example.SomeDependency" />
    </bean>
</beans>

2

Nhìn vào tốc độ phát triển của Springockitosố lượng các vấn đề mở , tôi sẽ hơi lo lắng khi giới thiệu nó vào ngăn xếp bộ thử nghiệm của mình ngày nay. Thực tế là bản phát hành cuối cùng đã được thực hiện trước khi bản phát hành Spring 4 đưa ra các câu hỏi như "Có thể dễ dàng tích hợp nó với Spring 4 không?". Tôi không biết, vì tôi đã không thử nó. Tôi thích cách tiếp cận Spring thuần túy nếu tôi cần chế nhạo Spring bean trong thử nghiệm tích hợp.

Có một tùy chọn để giả mạo Spring bean chỉ với các tính năng Spring đơn giản. Bạn cần sử dụng @Primary, @Profile@ActiveProfileschú thích cho nó. Tôi đã viết một bài blog về chủ đề này.


1

Tôi đã tìm thấy một câu trả lời tương tự như teabot để tạo ra một MockFactory cung cấp các giả. Tôi đã sử dụng ví dụ sau để tạo nhà máy giả (vì liên kết đến narkisr đã chết): http://hg.randompage.org/java/src/407e78aa08a0/projects/bookmarking/backend/spring/src/test/java/ org / randompage / bookmarking / backend / testUtils / MocksFactory.java

<bean id="someFacade" class="nl.package.test.MockFactory">
    <property name="type" value="nl.package.someFacade"/>
</bean>

Điều này cũng giúp ngăn chặn việc Spring muốn giải quyết việc tiêm từ hạt đậu bị chế giễu.


1
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
    <property name="type" value="com.package.Dao" />
</bean>

^ này hoạt động hoàn toàn tốt nếu được khai báo trước / sớm trong tệp XML. Mockito 1.9.0 / Mùa xuân 3.0.5


1

Tôi sử dụng kết hợp các cách tiếp cận được sử dụng trong câu trả lời của Markus T và một triển khai trình trợ giúp đơn giản ImportBeanDefinitionRegistrartìm kiếm một chú thích tùy chỉnh ( @MockedBeans) trong đó người ta có thể chỉ định các lớp nào sẽ bị chế giễu. Tôi tin rằng cách tiếp cận này dẫn đến một thử nghiệm đơn vị ngắn gọn với một số mã soạn sẵn liên quan đến việc nhạo báng bị loại bỏ.

Đây là cách thử nghiệm đơn vị mẫu với cách tiếp cận đó:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ExampleServiceIntegrationTest {

    //our service under test, with mocked dependencies injected
    @Autowired
    ExampleService exampleService;

    //we can autowire mocked beans if we need to used them in tests
    @Autowired
    DependencyBeanA dependencyBeanA;

    @Test
    public void testSomeMethod() {
        ...
        exampleService.someMethod();
        ...
        verify(dependencyBeanA, times(1)).someDependencyMethod();
    }

    /**
     * Inner class configuration object for this test. Spring will read it thanks to
     * @ContextConfiguration(loader=AnnotationConfigContextLoader.class) annotation on the test class.
     */
    @Configuration
    @Import(TestAppConfig.class) //TestAppConfig may contain some common integration testing configuration
    @MockedBeans({DependencyBeanA.class, DependencyBeanB.class, AnotherDependency.class}) //Beans to be mocked
    static class ContextConfiguration {

        @Bean
        public ExampleService exampleService() {
            return new ExampleService(); //our service under test
        }
    }
}

Để thực hiện điều này, bạn cần xác định hai lớp trình trợ giúp đơn giản - chú thích tùy chỉnh ( @MockedBeans) và ImportBeanDefinitionRegistrartriển khai tùy chỉnh . @MockedBeansđịnh nghĩa chú thích cần được chú thích @Import(CustomImportBeanDefinitionRegistrar.class)ImportBeanDefinitionRgistrarnhu cầu thêm các định nghĩa đậu giả vào cấu hình trong registerBeanDefinitionsphương thức của nó .

Nếu bạn thích cách tiếp cận, bạn có thể tìm thấy các triển khai mẫu trên blogpost của tôi .


1

Tôi đã phát triển một giải pháp dựa trên đề xuất của Kresimir Nesek. Tôi đã thêm một chú thích mới @EnableMockedBean để làm cho mã sạch hơn và mô-đun hơn một chút.

@EnableMockedBean
@SpringBootApplication
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=MockedBeanTest.class)
public class MockedBeanTest {

    @MockedBean
    private HelloWorldService helloWorldService;

    @Autowired
    private MiddleComponent middleComponent;

    @Test
    public void helloWorldIsCalledOnlyOnce() {

        middleComponent.getHelloMessage();

        // THEN HelloWorldService is called only once
        verify(helloWorldService, times(1)).getHelloMessage();
    }

}

Tôi đã viết một bài giải thích nó.


1

Tôi sẽ đề nghị chuyển dự án của bạn sang Spring Boot 1.4. Sau đó, bạn có thể sử dụng chú thích mới @MockBeanđể giả mạocom.package.Dao


0

Hôm nay tôi phát hiện ra rằng một bối cảnh mùa xuân nơi tôi đã tuyên bố trước hạt đậu Mockito, đã không tải được. Sau khi di chuyển SAU các giả, bối cảnh ứng dụng đã được tải thành công. Bảo trọng :)


1
Có gì đó bị thiếu. 8-) Bạn đã di chuyển những gì sau khi giả?
Hans-Peter Störr

0

Đối với bản ghi, tất cả các thử nghiệm của tôi hoạt động chính xác bằng cách chỉ làm cho vật cố được khởi tạo lười biếng, ví dụ:

<bean id="fixture"
      class="it.tidalwave.northernwind.rca.embeddedserver.impl.DefaultEmbeddedServer"
      lazy-init="true" /> <!-- To solve Mockito + Spring problems -->

<bean class="it.tidalwave.messagebus.aspect.spring.MessageBusAdapterFactory" />

<bean id="applicationMessageBus"
      class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="it.tidalwave.messagebus.MessageBus" />
</bean>

<bean class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="javax.servlet.ServletContext" />
</bean>

Tôi cho rằng lý do là một Mattias giải thích ở đây (ở cuối bài), rằng một cách giải quyết đang thay đổi thứ tự các hạt được khai báo - khởi tạo lười biếng là "loại" có kết quả cố định được khai báo ở cuối.


-1

Nếu bạn sử dụng Trình điều khiển tiêm, hãy đảm bảo các biến cục bộ của bạn KHÔNG "cuối cùng"

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.