봄 콩에 Mockito 모의 주입


284

JUnit을 사용한 단위 테스트를 위해 Mockito 모의 객체를 Spring (3+) Bean에 주입하고 싶습니다. 내 Bean 종속성은 현재 @Autowired개인 멤버 필드 의 주석을 사용하여 주입됩니다 .

사용을 고려 ReflectionTestUtils.setField했지만 주입하려는 Bean 인스턴스는 실제로 프록시이므로 대상 클래스의 개인 멤버 필드를 선언하지 않습니다. 테스트 목적으로 인터페이스를 순수하게 수정하므로 종속성에 대한 공용 세터를 만들고 싶지 않습니다.

Spring 커뮤니티에서 제공 한 조언 을 따랐 지만 모의가 생성되지 않고 자동 배선이 실패합니다.

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

현재 발생하는 오류는 다음과 같습니다.

...
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)

constructor-arg값을 잘못된 것으로 설정 하면 응용 프로그램 컨텍스트를 시작할 때 오류가 발생하지 않습니다.


4
이 작은 작은 생물을 살펴보십시오 : bitbucket.org/kubek2k/springockito/wiki/Home
kubek2k

이것은 매우 깨끗한 접근법입니다-나는 그것을 좋아합니다!
teabot

2
당신은 Springockito 주석에서 저를 가졌습니다.
yihtserns


2
스프링 4. *를 사용하는 사람들의 경우 2015 년 1 월 기준으로 최신 스프링 mockito 버전에서 작동하지 않는 것으로 보이며 프로젝트가 비활성화 된 것으로 보입니다.
Murali

답변:


130

가장 좋은 방법은 다음과 같습니다.

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

업데이트
컨텍스트 파일에서이 모형은 선언 된대로 자동 유선 필드보다 먼저 나열되어야합니다.


"이름이 'mockito'인 Bean을 작성하는 중에 오류 발생 : Bean 정의가
추 상임

4
@ amra : spring 은이 경우 반환되는 객체의 유형을 유추하지 않습니다 ... stackoverflow.com/q/6976421/306488
lisak

7
이 답변이 왜 그렇게 많이 찬성되었는지 모릅니다. 결과 Bean은 유형이 잘못되어 자동 와이어 링 될 수 없습니다.
azerole

4
컨텍스트 파일에 처음으로 나열되면 (자동 연결 필드가 선언되기 전에) 자동 연결될 수 있습니다.
Ryan Walls

3
봄 3.2부터는 콩의 순서가 더 이상 중요하지 않습니다. 이 블로그 게시물의 "Generic Factory Methods"섹션을 참조하십시오 : spring.io/blog/2012/11/07/…
Ryan Walls

110
@InjectMocks
private MyTestObject testObject;

@Mock
private MyDependentObject mockedObject;

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

이것은 조롱 된 객체를 테스트 클래스에 주입합니다. 이 경우 mockedObject를 testObject에 주입합니다. 이것은 위에서 언급되었지만 여기에 코드가 있습니다.


1
특정 방법을 mockedObject어떻게 스텁 합니까?
Jim Holden

@Teinacher when (mockedObject.execute) .thenReturn (objToReturn); 이전 방법이나 테스트 방법에 넣을 수 있습니다.
혼돈 이론

40
참고 : MyTestObject에서 부분 자동 배선 및 부분 조롱을 원하면이 방법이 작동하지 않습니다.
raksja

9
왜 이것이 더 높은 투표를했는지 모르겠습니다. XML이 포함 된 답변이 더 있으면 내가 던질 것입니다.
MarkOfHall

3
왜 대신 Mockito.spy(...)에 이것을 mockedObject사용하지 않습니까? 그런 다음 when(mockedObject.execute).thenReturn(objToReturn)또는 을 사용하십시오 doReturn(objToReturn).when(mockedObject).execute(). 두 번째는 실제 메소드를 호출하지 않습니다. Mockito.doCallRealMethod()문서 를 확인할 수도 있습니다
Tomasz Przybylski

63

Spring Java Config 및 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
이 접근 방식을 사용하는 어떤 이유로 봄은 어쨌든 실제 콩을 만들려고 시도하고 모의 대신 질식시킵니다 ... 내가 잘못한 것은 무엇입니까?
Daniel Gruszczyk

1
같은 문제가 있습니다
Korobko Alex

3
봄이 아니라 오히려 mockito는 클래스를 조롱하는 경우 실제 콩을 인스턴스화하려고 시도합니다. 테스트에서 조롱해야 할 Bean이 있으면 인터페이스의 구현이어야하고 해당 인터페이스를 통해 주입되어야합니다. 그런 다음 클래스가 아닌 인터페이스를 조롱하면 mockito는 해당 클래스를 인스턴스화하려고 시도하지 않습니다.
Daniel Gruszczyk

7
요점이 뭐야? 주석이 달린 필드와 생성자를 왜 initMocks? 왜 그냥 return Mockito.mock(BeanA.class)에서 getBeanA? 이렇게하면 더 간단하고 코드가 적습니다. 내가 무엇을 놓치고 있습니까?
Oleg

1
@Oleg 그것은 당신이 자신의 솔루션을 가지고있는 것처럼 들리 며, 아마도 답변으로 게시해야 커뮤니티가 투표 할 수 있습니다.
Dawood ibn Kareem

48

주어진:

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

    // etc
}

자동 배선을 통해 테스트중인 클래스를로드하고 Mockito와의 종속성을 모의 한 다음 Spring의 ReflectionTestUtils를 사용하여 테스트중인 클래스에 모의 객체를 주입 할 수 있습니다.

@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
}

Spring 4.3.1 이전에는이 ​​메소드가 프록시 뒤의 서비스 ( 예 : @Transactional, 또는 Cacheable)로 작동하지 않습니다 . 이것은 SPR-14050에 의해 수정되었습니다 .

이전 버전의 경우 해결책은 다음과 같이 프록시 래핑을 해제하는 것입니다. 트랜잭션 주석은 서비스가 조롱되는 것을 방지합니다 ( ReflectionTestUtils.setField현재 기본적으로 수행되는 작업).


@RunWith (SpringJUnit4ClassRunner.class)를 두 번 만들고 테스트 클래스 (동일한 러너)에 다른 주석을 사용하지만이 방법은 저에게 효과적입니다.
user1317422

1
"Spr 4.3.1 이전에는이 ​​메소드가 프록시 뒤의 서비스 (예 : @Transactional 또는 Cacheable로 주석 처리됨)에서 작동하지 않는다는 점에 많은 영감을 받았습니다. 이는 SPR-14050으로 수정되었습니다." 방금이 문제에 부딪 쳤 으며이 단어를 발견 할 때까지 아무런 단서도 얻지 못했습니다. 많은 감사합니다!
snowfox

1
이 솔루션은 전체 애플리케이션 컨텍스트를 연결하고 테스트 목적으로 컨텍스트의 임의의 Bean에 모의를 삽입하려고 할 때 처리합니다. 모듈 테스트에서 다른 모듈에 대한 REST 호출을 피하기 위해이 대답을 사용하여 가짜 클라이언트 Bean을 조롱했습니다. Spring 애플리케이션 구성으로 작성된 Bean이 아닌 테스트하려는 Bean에 모의 객체를 주입 할 때 InjectMock 주석이 작동합니다.
Andreas Lundgren

1
거의 하루 종일 @MockBean을 컨텍스트를 재설정하지 않고 작동 시키려고 노력한 후이 보석을 발견했습니다. 정확히 내가 필요한 것은, 건배.
Matt R

캐싱으로 인해 교체 된 필드가 재설정되지 않을 수 있으며 관련되지 않은 일부 테스트가 중단 될 수 있음에 유의하십시오. 예를 들어 내 테스트에서 암호 인코더를 모의 코드로 교체했으며 인증 실패로 인해 몇 가지 다른 테스트가 중단되었습니다.
alextsil

36

Spring Boot 1.4를 사용하는 경우이 작업을 수행하는 멋진 방법이 있습니다. @SpringBootTest수업과 @MockBean현장 에서 새로운 브랜드 를 사용하기 만하면 Spring Boot는이 유형의 모형을 만들어 문맥에 주입합니다 (원래 브랜드 를 주입하는 대신).

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

}

반면에 Spring Boot를 사용하지 않거나 이전 버전을 사용하는 경우 약간 더 많은 작업을 수행해야합니다.

@ConfigurationSpring 컨텍스트에 모의 객체를 주입 하는 Bean을 작성하십시오 .

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

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

@Primary주석을 사용하면 한정자가 지정되지 않은 경우이 bean이 우선 순위를 갖도록 스프링에 알립니다.

@Profile("useMocks")모의를 사용할 클래스와 실제 Bean을 사용할 클래스를 제어 하려면 클래스에 주석을 달아야합니다 .

마지막으로 테스트에서 userMocks프로파일을 활성화하십시오 .

@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() {
        ....
    }
}

mock을 사용하고 싶지 않고 실제 bean을 사용하고 싶다면 useMocks프로파일을 활성화하지 마십시오 .

@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
이 답변은 맨 위로 이동해야합니다-스프링 부트에서 @MockBean 지원도 스프링 부트없이 사용할 수 있습니다. 단위 테스트에서만 사용할 수 있으므로 모든 스프링 애플리케이션에서 작동합니다!
bedrin

2
@Profile 주석 당신은 별도의 설정 클래스를 만드는 것을 피하기 위해 빈 정의 메소드에서도 설정할 수 있습니다
marcin

좋은 답변입니다! 구식 web.xml및 AnnotationConfigWebApplicationContext 설정에서 작동하도록 몇 가지 사항을 변경했습니다 . 사용했다 @WebAppConfiguration대신 @WebIntegrationTest@ContextHierarchy함께 @ContextConfiguration대신 @SpringApplicationConfiguration.
UTF_or_Death

내가 조롱하고 싶었던 @Primary내부에 실패한 호출이 있었기 때문에 내 사례에 주석 을 추가해야 @PostConstruct했지만 @PostConstructmock을 사용하지 않도록 (모두 추가 할 때까지 @Primary) mock을 내 mock 전에 만들었습니다 .
helleye

19

Mockito는 1.8.3 부터 @InjectMocks-이것은 매우 유용합니다. 내 JUnit 테스트는 @RunWithMockitoJUnitRunner나는 구축 @Mock개인 회원이 주석 때 모든 주입되는 클래스에 대한 모든 종속성이 테스트되고 만족 객체 @InjectMocks.

I 만 지금은 통합 테스트합니다.@RunWithSpringJUnit4Runner

List<T>스프링과 같은 방식으로 주사 할 수없는 것 같습니다 . 를 만족하는 Mock 객체 만 찾고 Mock 객체 List목록을 삽입하지 않습니다. 해결 방법 @Spy은 수동으로 인스턴스화 된 목록에 대해 를 사용하고 단위 테스트를 위해 모의 객체를 해당 목록에 수동으로 추가하는 것입니다. 어쩌면 그것은 의도적이었습니다. 왜냐하면 그것은 함께 조롱 된 것에주의를 기울여야했기 때문입니다.


네 이것이 최선의 방법입니다. Springockito는 실제로 어떤 경우에도 모의를 주입하지 않습니다.
혼돈 이론

13

업데이트 : 이제이 문제에 대한 더 나은 해결책이 있습니다. 다른 답변을 먼저 고려하십시오.

나는 결국 그의 블로그에서 ronen이 이에 대한 답변을 찾았습니다. 내가 겪고있는 문제는 Mockito.mock(Class c)의 반환 유형을 선언하는 메서드 때문 입니다 Object. 결과적으로 Spring은 팩토리 메소드 리턴 유형에서 Bean 유형을 유추 할 수 없습니다.

Ronen의 솔루션FactoryBean모의를 반환 하는 구현 을 만드는 것입니다. FactoryBean인터페이스는 봄이 공장 콩으로 만든 개체의 유형을 쿼리 할 수 있습니다.

내 조롱 된 콩 정의는 다음과 같습니다.

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

1
Ronen 솔루션에 대한 업데이트 된 링크 : narkisr.com/blog/2008/2647754885089732945
Jeff Martin

나는 그것을 이해하지 못하고, 팩토리 메소드는 반환 형식 개체를 가지고 ...하지만 AMRA의 솔루션은 봄이 그것을 인식해야 너무 일반적인 반환 유형이 ... 그러나 AMRA의 솔루션은 나를 위해 일을하지 않습니다
lisak

이 솔루션도 스프링은 factoryBean에서 리턴 된 Bean의 유형을 유추하지 않습니다. 따라서 [com.package.Dao] 유형의 일치하는 Bean이 없습니다.
lisak


이 링크는 실제로 계속 작동합니다. javadevelopmentforthemasses.blogspot.com/2008/07/… 브라우저에서 링크 리디렉션을 비활성화하면 새 블로그에서 404를 보지 않아도 링크 리디렉션이 표시됩니다.
aboutiblue

12

Spring 3.2부터는 더 이상 문제가되지 않습니다. Spring은 이제 일반적인 팩토리 메소드 결과의 자동 배선을 지원합니다. 이 블로그 게시물 ( http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/) 에서 "Generic Factory Methods"라는 제목의 섹션을 참조 하십시오 .

핵심은 다음과 같습니다.

Spring 3.2에서는 팩토리 메소드의 일반 리턴 유형이 올바르게 추론되고 모의 유형별 자동 배선이 예상대로 작동합니다. 결과적으로 MockitoFactoryBean, EasyMockFactoryBean 또는 Springockito와 같은 사용자 정의 해결 방법은 더 이상 필요하지 않습니다.

이것은 이것이 즉시 작동해야 함을 의미합니다.

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

9

아래 코드는 자동 배선과 함께 작동합니다. 가장 짧은 버전은 아니지만 표준 스프링 / mockito 항아리에서만 작동해야 할 때 유용합니다.

<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> 

나를 위해 일했다. 다음에 설명 된대로 확인하기 위해 테스트에서 프록시를 풀어야
Holgzn

9

당신이 사용하는 경우 봄> = 3.0 , 스프링스 사용해보십시오 @Configuration애플리케이션 컨텍스트의 일부를 정의하는 주석을

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

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

}

@ImportResource를 사용하지 않으려면 다른 방법으로도 수행 할 수 있습니다.

<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>

자세한 내용은 spring-framework-reference : Java 기반 컨테이너 구성을 살펴보십시오.


좋은데 테스트중인 테스트가 실제 테스트 사례에서 @Autowired 일 때 이것을 사용했습니다.
enkor

8

아마도 완벽한 솔루션은 아니지만 단위 테스트를 위해 DI를 수행하기 위해 스프링을 사용하지 않는 경향이 있습니다. 단일 빈 (테스트중인 클래스)에 대한 종속성은 일반적으로 지나치게 복잡하지 않으므로 테스트 코드에서 직접 주입을 수행합니다.


3
당신의 접근 방식을 이해합니다. 그러나 나는이 상황에서 자신을 쉽게 허용하지 않는 큰 레거시 코드베이스를 발견했습니다.
teabot

1
Mockito / Spring 콤보는 Spring aspect / AOP에 크게 의존하는 코드를 테스트해야 할 때 (예 : 스프링 보안 규칙을 테스트 할 때) 매우 유용한 것으로 나타났습니다. 그러한 테스트는 통합 테스트 여야한다고 주장하는 것이 완벽하게 정당화되지만.
Lars Tackmann

@Lars-동의-내가 다루는 테스트에 대해 동일하게 말할 수 있습니다.
teabot

7

Mockito를 사용하여 다음을 수행 할 수 있습니다.

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

1
답변 @Alexander에 감사드립니다. 물어봐도 될까요 : 올바르게 배선되어 있습니까? 그렇다면 어떤 버전의 Spring / Mockito를 사용하고 있습니까?
teabot

6

위의 접근 방식을 기반으로 몇 가지 예 게시

봄 :

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

봄없이 :

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

2

업데이트 -새로운 답변은 https://stackoverflow.com/a/19454282/411229 입니다. 이 답변은 3.2 이전 스프링 버전의 답변에만 적용됩니다.

나는 이것에 대한보다 확실한 해결책을 찾기 위해 잠시 동안 보았다. 이 블로그 게시물은 모든 요구 사항을 다루는 것으로 보이며 Bean 선언의 순서에 의존하지 않습니다. Mattias Severson의 모든 크레딧. http://www.jayway.com/2011/11/30/spring-integration-tests-part-i-creating-mock-objects/

기본적으로 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;
    }
}

다음으로 스프링 설정을 다음과 같이 업데이트하십시오.

<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

Springockito 개발 속도공개 이슈 수를 살펴보면 요즘 테스트 스위트 스택에 도입하는 것이 조금 걱정됩니다. Spring 4 릴리스 이전에 마지막 릴리스가 완료된 사실은 "Spring 4와 쉽게 통합 할 수 있습니까?"와 같은 질문을합니다. 나는 그것을 시도하지 않았기 때문에 모른다. 통합 테스트에서 Spring bean을 조롱 해야하는 경우 순수한 Spring 접근법을 선호합니다.

일반 스프링 기능만으로 스프링 빈을 가짜로 만드는 옵션이 있습니다. 당신은 사용할 필요가 @Primary, @Profile그리고 @ActiveProfiles그것에 대한 주석. 주제에 대한 블로그 게시물을 작성했습니다.


1

모의를 제공하는 MockFactory를 만드는 teabot과 비슷한 대답을 찾았습니다. 나는 (narkisr에 대한 링크가 죽은 이후) 모의 공장을 만들려면 다음 예를 사용 : 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>

이것은 또한 Spring이 조롱 된 콩에서 주입을 해결하려는 것을 방지하는 데 도움이됩니다.


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

이 ^는 XML 파일에서 처음 / 초기 선언되면 완벽하게 작동합니다. 모키 토 1.9.0 / 봄 3.0.5


1

Markus T의 답변에 사용 된 접근 방식과 조롱 할 클래스를 지정할 수 ImportBeanDefinitionRegistrar있는 사용자 정의 주석 ( @MockedBeans) 을 찾는 간단한 도우미 구현을 조합하여 사용합니다 . 이 접근 방식을 사용하면 조롱과 관련된 상용구 코드를 사용하여 간결한 단위 테스트가 수행된다고 생각합니다.

다음은 이러한 접근 방식으로 샘플 단위 테스트를 보는 방법입니다.

@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
        }
    }
}

이를 위해서는 두 가지 간단한 도우미 클래스 인 맞춤 주석 (@MockedBeans )과 사용자 지정 ImportBeanDefinitionRegistrar구현을 정의 해야합니다. @MockedBeans주석 정의의 요구로 주석 할 @Import(CustomImportBeanDefinitionRegistrar.class)과는 ImportBeanDefinitionRgistrar그것의의 구성에 조롱 콩 정의를 추가해야 registerBeanDefinitions하는 방법.

당신이 접근 방식을 좋아한다면 내 블로그 포스트 에서 샘플 구현 을 찾을 수 있습니다 .


1

Kresimir Nesek의 제안에 따라 솔루션을 개발했습니다. 코드를 좀 더 깨끗하고 모듈화하기 위해 새로운 주석 @EnableMockedBean 을 추가했습니다 .

@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();
    }

}

나는 그것을 설명 하는 게시물 을 작성 했습니다.



0

오늘 나는 Mockito bean 이전에 선언 한 스프링 컨텍스트가로드되지 않았다는 것을 알았습니다. 모의 후에 이동 한 후 앱 컨텍스트가 성공적으로로드되었습니다. 조심하세요 :)


1
빠진 것이 있습니다. 8-) 모의 후 무엇을 옮겼습니까?
Hans-Peter Störr

0

기록을 위해 모든 테스트는 조명기를 지연 초기화하여 다음과 같이 올바르게 작동합니다.

<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>

나는 이론적 근거가 Mattias가 여기 (포스트의 맨 아래)에서 설명하는 것이라고 생각합니다. 해결책은 콩이 선언 된 순서를 변경하고 있다고 가정합니다. 게으른 초기화는 끝 부분에 픽스처가 선언 된 "정렬"입니다.


-1

Controller Injection을 사용하는 경우 지역 변수가 "최종"이 아닌지 확인하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.