Mockito : 모의 비공개 필드 초기화


95

인라인으로 초기화되는 필드 변수를 어떻게 모의 할 수 있습니까?

class Test {
    private Person person = new Person();
    ...
    public void testMethod() {
        person.someMethod();
        ...
    }
}

여기 에서는 변수 초기화를 모의해야하는 메서드를 person.someMethod()테스트하는 동안 모의하고 싶습니다 . 단서가 있습니까?Test.testMethod()person

편집 : Person 클래스를 수정할 수 없습니다.


1
이 링크는 당신에게 도움이 될 수 stackoverflow.com/questions/13645571/...
뽀빠이

2
.NET 용 모의 파일을 전달할 수 있도록 코드를 리팩터링해야합니다 Person. 옵션에는 생성자 추가 또는 setter 메서드 추가가 포함됩니다.
팀 Biegeleisen

답변:


109

Mockito에는 일부 리플렉션 보일러 플레이트 코드를 저장하는 도우미 클래스가 있습니다.

import org.mockito.internal.util.reflection.Whitebox;

//...

@Mock
private Person mockedPerson;
private Test underTest;

// ...

@Test
public void testMethod() {
    Whitebox.setInternalState(underTest, "person", mockedPerson);
    // ...
}

업데이트 : 불행하게도 mockito 팀은 결정 클래스를 제거하는 또 다른 라이브러리 (예를 들어, 사용, 다시 자신의 반사 상용구 코드를 작성하는 그래서 Mockito 2에 아파치 코 몬즈 랭을 , 또는 단순히 붙잡을) 화이트 박스 클래스 (그것이 MIT 라이센스 ).

업데이트 2 : JUnit 5는 유용 할 수있는 자체 ReflectionSupportAnnotationSupport 클래스 와 함께 제공되며 또 다른 라이브러리를 가져 오지 않아도됩니다 .


다른 이유로 대상 개체를 감시하고 있으며이 경우 개체가 스파이 인 경우 이러한 방식으로 내부 상태를 설정할 수 없습니다.
Arun

왜 안돼? 스파이와 함께 사용하고 있습니다. Person 인스턴스를 만듭니다. 스터 빙이 필요한 것은 무엇이든 스터 빙 한 다음 테스트 인스턴스에서 설정합니다.
Ralf

경고 : internalWhitebox 는 패키지에 포함되어 있으며 Mockito 2.6.2에서 더 이상 작동하지 않는 것 같습니다.
Nova

FieldSetter.setField ()를 사용할 수 있습니다. 나는 동일한 예를 아래에 제시했습니다.
Raj Kumar

1
@Ralf Java에서 참조 이름을 변경하면 항상 컴파일 오류가 발생하기 때문입니다.
Joe Coder 2019

69

파티에 꽤 늦었지만 여기에서 쳐서 친구의 도움을 받았습니다. 문제는 PowerMock을 사용하지 않는 것이 었습니다. 이것은 최신 버전의 Mockito에서 작동합니다.

Mockito는 이것과 함께 제공됩니다 org.mockito.internal.util.reflection.FieldSetter.

기본적으로 리플렉션을 사용하여 개인 필드를 수정하는 데 도움이됩니다.

사용 방법은 다음과 같습니다.

@Mock
private Person mockedPerson;
private Test underTest;

// ...

@Test
public void testMethod() {
    FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);
    // ...
    verify(mockedPerson).someMethod();
}

이렇게하면 모의 객체를 전달한 다음 나중에 확인할 수 있습니다.

다음 은 참고 자료입니다.


FieldSetterMockito 2.x에서는 더 이상 사용할 수 없습니다.
Ralf

4
@Ralf 나는 버전 mockito-core-2.15.0을 사용하고 있습니다. 거기에서 사용할 수 있습니다. static.javadoc.io/org.mockito/mockito-core/2.0.15-beta/org/... . 그래도 여전히 베타입니다.
Raj Kumar

1
@RajKumar Class#getDeclaredField는 단일 매개 변수를 허용하므로 괄호는 다음과 같아야합니다 FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);. 그것이 내가 잘못한 방법이며 귀하의 예에서 그것을 고치는 것이 좋은 생각이라고 생각했습니다. 답장 해 주셔서 감사합니다.
Dapeng Li

1
내부 API를 사용하는 것이 가장 좋은 생각이 아니다
데이비드

@RajKumar 멋지지만 Zimbo Rodger가 언급했듯이 내부 API를 사용하는 것이 좋은 생각입니까? 왜 그것은 내부적 인 것입니까? 테스트에 매우 유용합니다.
Willi Mentzel

32

Spring Test를 사용하는 경우 org.springframework.test.util.ReflectionTestUtils를 시도하십시오.

 ReflectionTestUtils.setField(testObject, "person", mockedPerson);

1
큰! 이 기사에 링크하는 데 도움이 될 수 있으며 필요한 종속성을 포함 할 수 있습니다. baeldung.com/spring-reflection-test-utils
Willi Mentzel

build.gradle.kts :testImplementation("org.springframework:spring-test:5.1.2.RELEASE")
Willi Mentzel

28

나는 이미 여기에 게시하는 것을 잊은이 문제에 대한 해결책을 찾았습니다.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Test.class })
public class SampleTest {

@Mock
Person person;

@Test
public void testPrintName() throws Exception {
    PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
    Test test= new Test();
    test.testMethod();
    }
}

이 솔루션의 핵심 사항은 다음과 같습니다.

  1. PowerMockRunner로 테스트 케이스 실행 : @RunWith(PowerMockRunner.class)

  2. Powermock에게 Test.class비공개 필드의 조작 을 준비하도록 지시 합니다.@PrepareForTest({ Test.class })

  3. 마지막으로 Person 클래스의 생성자를 모의합니다.

    PowerMockito.mockStatic(Person.class); PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);


8
설명은 mockStatic함수 에 대해 설명 하지만 코드 예제에는 표시되지 않습니다. 코드 예제에 mockStatic호출 이 있어야합니까 , 아니면 생성자에 필요하지 않습니까?
Shadoninja 2010 년

10

다음 코드는 REST 클라이언트 모의에서 매퍼를 초기화하는 데 사용할 수 있습니다. 이 mapper필드는 비공개이며 단위 테스트 설정 중에 설정해야합니다.

import org.mockito.internal.util.reflection.FieldSetter;

new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());

5

@Jarda의 가이드를 사용하면 모든 테스트에 대해 동일한 값으로 변수를 설정해야하는 경우이를 정의 할 수 있습니다.

@Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
    FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}

그러나 개인 값을 다르게 설정하는 것은주의해서 처리해야합니다. 그들이 사적인 경우 어떤 이유로 든입니다.

예를 들어 단위 테스트에서 수면 대기 시간을 변경하는 데 사용합니다. 실제 예에서는 10 초 동안 자고 싶지만 단위 테스트에서는 즉각적이면 만족합니다. 통합 테스트에서는 실제 값을 테스트해야합니다.

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