Mockito : 개인 @Autowired 필드에 실제 객체 주입


191

Mockito @Mock@InjectMocks주석을 사용하여 Spring으로 주석이 달린 개인 필드에 종속성을 주입합니다 @Autowired.

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
    @Mock
    private SomeService service;

    @InjectMocks
    private Demo demo;

    /* ... */
}

public class Demo {

    @Autowired
    private SomeService service;

    /* ... */
}

이제 실제 객체를 @Autowiredsetter없이 개인 필드에 주입하고 싶습니다 . 이것이 가능합니까 아니면 메커니즘은 Mocks 주입에만 국한됩니까?


5
일반적으로 물건을 조롱 할 때, 구체적인 대상에 대해서는 신경 쓰지 않습니다. 조롱 된 대상의 행동에만 관심이 있다는 것입니다. 아마도 통합 테스트를하고 싶습니까? 아니면 왜 모의되고 구체적인 물체가 함께 살기를 원하는지에 대한 이론적 근거를 제공 할 수 있습니까?
Makoto

2
글쎄, 레거시 코드를 다루고 있으며 일부 NPE 등을 막기 위해 모의를 설정하려면 많은 when (...). thenReturn (...) 문이 필요합니다. 반면에 실제 객체를 안전하게 사용할 수 있습니다. 따라서 모의 객체와 함께 실제 물체를 주입하는 옵션을 갖는 것이 매우 편리합니다. 이것이 코드 냄새일지도 모르지만, 나는이 특별한 경우에 합리적이라고 생각합니다.
user2286693

MockitoAnnotations.initMocks(this);@Before방법을 잊지 마십시오 . 나는 그것이 원래의 질문과 직접적으로 관련이 없다는 것을 알고 있지만 나중에 나올 사람에게는 이것을 실행할 수 있도록 추가해야합니다.
Cuga

7
@Cuga : JUnit에 Mockito 러너를 사용한다면 ( @RunWith(MockitoJUnitRunner.class)) 라인이 필요 없습니다MockitoAnnotations.initMocks(this);
Clint Eastwood

1
고마워-나는 그것을 알지 못하고 항상 두 가지 모두를 지정했습니다
Cuga

답변:


306

@Spy주석 사용

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
    @Spy
    private SomeService service = new RealServiceImpl();

    @InjectMocks
    private Demo demo;

    /* ... */
}

Mockito는 주석으로 주석이 달린 인스턴스에 삽입 될 잠재적 후보로서 모든 필드 @Mock또는 @Spy주석을 고려합니다 @InjectMocks. 위의 경우 'RealServiceImpl'인스턴스는 '데모'에 주입됩니다.

자세한 내용은

모키 토 홈

@스파이

@모조품


9
+1 : 나를 위해 일했습니다 ... String 객체를 제외하고. Mockito는 다음과 같이 불평합니다 :Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types
Adrian Pronk

고마워 그것은 나를 위해 일했다 :) 프록시가 실제 구현을 위해 다른 것을 모의로 사용하려면 스파이
Swarit Agarwal

감사! 바로 내가 필요한 것입니다!
nterry

2
제 경우에는 Mockito가 스파이를 주입 하지 않습니다 . 그래도 모의를 주입합니다. 이 필드는 비공개이며 세터가 없습니다.
Vituel

8
BTW는 필요가 없으며 new RealServiceImpl(), @Spy private SomeService service;어쨌든 감시하기 전에 기본 생성자를 사용하여 실제 객체를 만듭니다.
parxier

20

@Dev Blanked 응답 추가에서 Spring이 만든 기존 Bean을 사용하려는 경우 코드를 다음과 같이 수정할 수 있습니다.

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {

    @Inject
    private ApplicationContext ctx;

    @Spy
    private SomeService service;

    @InjectMocks
    private Demo demo;

    @Before
    public void setUp(){
        service = ctx.getBean(SomeService.class);
    }

    /* ... */
}

이렇게하면 테스트를 수행하기 위해 코드를 변경하거나 다른 생성자를 추가 할 필요가 없습니다.


2
@Aada 정교하게 할 수 있습니까?
아즈 멘다

1
이 라이브러리는 어떤 라이브러리에서 왔으며 org.mockito의 InjectMocks 만 볼 수 있습니다
Sameer

1
@sameer import org.mockito.InjectMocks;
Yoaz Menda 2016

Aada를 취소하기위한 주석 추가. 이것은 나를 위해 일했습니다. 다른 답변에서 제안한대로 "필드 주입을 간단히 사용할 수 없습니다"는 것은 불가능하므로 Autowired종속성 의 필드가 올바르게 작성되었는지 확인해야했습니다 .
Scrambo

1
나는 이것을 시도했다. 하지만 난 설정 방법에서 널 포인터 예외를 수신하고
아킬 Surapuram

3

Mockito는 DI 프레임 워크가 아니며 DI 프레임 워크조차도 필드 주입보다 생성자 주입을 권장합니다.
따라서 테스트중인 클래스의 종속성을 설정하기 위해 생성자를 선언하면됩니다.

@Mock
private SomeService serviceMock;

private Demo demo;

/* ... */
@BeforeEach
public void beforeEach(){
   demo = new Demo(serviceMock);
}

spy일반적인 경우에 Mockito 를 사용 하는 것은 끔찍한 조언입니다. 그것은 테스트 클래스를 직진하지 않고 취하기 쉽고 오류가 발생하기 쉽습니다. 실제로 조롱되는 것은 무엇입니까? 실제로 무엇을 테스트합니까?
@InjectMocks그리고 @Spy이 클래스에서 비 대한 클래스와 혼합 책임을 장려하기 때문에 또한 전체 디자인을 아파요.
제발 읽기 spy()javadoc는 (강조 광산하지 않습니다) 그 맹목적으로 사용하기 전에 :

실제 개체의 스파이를 만듭니다. 스파이 전화 는 스텁되지 않는 한 실제 메소드를 . 실제 스파이는 예를 들어 레거시 코드를 처리 할 때 신중하고 가끔 사용해야합니다 .

평소와 같이 partial mock warning: 객체 지향 프로그래밍은 복잡성을 별도의 특정 SRPy 객체로 나누어 복잡성을 해결합니다. 부분 모의가이 패러다임에 어떻게 맞습니까? 글쎄, 그것은 단지 ... 부분 모의는 복잡성이 동일한 객체에서 다른 방법으로 이동되었음을 의미합니다. 대부분의 경우 이것은 응용 프로그램을 디자인하려는 방식이 아닙니다.

그러나 부분 모의가 유용한 경우는 드물다. 코드를 다루기 만하면 쉽게 변경할 수 없다 (타사 인터페이스, 레거시 코드의 중간 리팩토링 등). 그러나 테스트 중심의 새로운 모의를 위해 부분 모의를 사용하지는 않을 것이다. 설계된 코드.


0

Spring에는 ReflectionTestUtils이 목적을위한 전용 유틸리티가 있습니다. 특정 예를 들어 현장에 주입하십시오.


@Spy
..
@Mock
..

@InjectMock
Foo foo;

@BeforeEach
void _before(){
   ReflectionTestUtils.setField(foo,"bar", new BarImpl());// `bar` is private field
}

-1

나는 이것이 오래된 질문이라는 것을 알고 있지만 문자열을 주입하려고 할 때 같은 문제에 직면했습니다. 그래서 우리는 정확히 원하는 것을 수행하는 JUnit5 / Mockito 확장을 발명했습니다. https://github.com/exabrial/mockito-object-injection

편집하다:

@InjectionMap
 private Map<String, Object> injectionMap = new HashMap<>();

 @BeforeEach
 public void beforeEach() throws Exception {
  injectionMap.put("securityEnabled", Boolean.TRUE);
 }

 @AfterEach
 public void afterEach() throws Exception {
  injectionMap.clear();
 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.