@Mock과 @InjectMocks의 차이점


답변:


542

@Mock모의를 만듭니다. @InjectMocks클래스의 인스턴스를 만들고 @Mock(또는 @Spy) 주석으로 만든 모형을 이 인스턴스에 삽입합니다.

사용해야합니다 @RunWith(MockitoJUnitRunner.class)또는 Mockito.initMocks(this)그들을 이러한 모의 객체를 초기화하고 주입 할 수 있습니다.

@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {

    @InjectMocks
    private SomeManager someManager;

    @Mock
    private SomeDependency someDependency; // this will be injected into someManager

     //tests...

}

2
짧고 간결한 답변. 도움도)
Chaklader Asfak Arefe

이것은 전 이적 의존성 또는 직접적인 회원에게만 효과가 있습니까?
Pierre Thibault가

@PierreThibault Injecting mocks는 직접 멤버에게만 작동하지만 딥 스텁을 허용하도록 mock을 설정할 수 있습니다. static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/…
Tom Verelst

1
나는이가 .... 온라인 기사의 대부분보다 훨씬 분명하다 느낀다 내 엉덩이 저장 작은 의견 ...
IHC_Applroid

컨텍스트와 같은 @Mock 주석으로 제공 할 수없는 항목이 있습니다. 메인 클래스에 어떻게 제공 할 수 있습니까?
Mahdi

220

이것은 어떻게 @Mock그리고 @InjectMocks작동 하는지에 대한 샘플 코드입니다 .

우리가 말 GamePlayer클래스입니다.

class Game {

    private Player player;

    public Game(Player player) {
        this.player = player;
    }

    public String attack() {
        return "Player attack with: " + player.getWeapon();
    }

}

class Player {

    private String weapon;

    public Player(String weapon) {
        this.weapon = weapon;
    }

    String getWeapon() {
        return weapon;
    }
}

보시다시피 Game클래스는 Player을 수행해야합니다 attack.

@RunWith(MockitoJUnitRunner.class)
class GameTest {

    @Mock
    Player player;

    @InjectMocks
    Game game;

    @Test
    public void attackWithSwordTest() throws Exception {
        Mockito.when(player.getWeapon()).thenReturn("Sword");

        assertEquals("Player attack with: Sword", game.attack());
    }

}

Mockito는 Player 클래스를 조롱하고 사용 whenthenReturn메소드 동작 입니다. 마지막으로, 사용 @InjectMocksMockito하면 해당 넣을 것 Player으로 Game.

new Game객체 를 만들 필요조차 없습니다 . Mockito가 당신을 위해 그것을 주입합니다.

// you don't have to do this
Game game = new Game(player);

우리는 또한 @Spy주석을 사용하여 동일한 동작을 얻을 것 입니다. 속성 이름이 다른 경우에도 마찬가지입니다.

@RunWith(MockitoJUnitRunner.class)
public class GameTest {

  @Mock Player player;

  @Spy List<String> enemies = new ArrayList<>();

  @InjectMocks Game game;

  @Test public void attackWithSwordTest() throws Exception {
    Mockito.when(player.getWeapon()).thenReturn("Sword");

    enemies.add("Dragon");
    enemies.add("Orc");

    assertEquals(2, game.numberOfEnemies());

    assertEquals("Player attack with: Sword", game.attack());
  }
}

class Game {

  private Player player;

  private List<String> opponents;

  public Game(Player player, List<String> opponents) {
    this.player = player;
    this.opponents = opponents;
  }

  public int numberOfEnemies() {
    return opponents.size();
  }

  // ...

Mockito Type SignaturePlayer및 의 게임 클래스를 확인하기 때문 List<String>입니다.


16
이 예에서는 허용되는 답변이어야합니다.
AnnaKlein

4
나는 이것이 또한 가장 좋은 생각이라고 생각한다
Evgeniy Dorofeev

4
나는 이것이 최고의 답변 트리플이라고 생각합니다.
Harvey Dent

1
때로는 모의 테스트를 이해하고 수업을 디자인하기가 어렵다는 것을 알게됩니다. 그러나이 예제는 개요를 제공하는 데 많은 도움이됩니다.
Chaklader Asfak Arefe

1
많은 감사 :) 더 나은 설명으로 요점.
Rishi

80

테스트 클래스에서 테스트 된 클래스에는 주석을 달아야합니다 @InjectMocks. 이것은 Mockito에게 mock을 주입 할 클래스를 알려줍니다 :

@InjectMocks
private SomeManager someManager;

그런 다음 클래스 내부의 특정 메소드 또는 객체 (이 경우) SomeManager가 모의 객체로 대체되도록 지정할 수 있습니다.

@Mock
private SomeDependency someDependency;

이 예제에서는 클래스 SomeDependency내부 SomeManager가 조롱됩니다.


6
someManager에 둘 이상의 생성자가있는 경우이 작동합니까? someManager에 5 개의 생성자가 있으면 어떤 것을 사용하고 싶은지 어떻게 알 수 있습니까?
j2emanue 2013

51

@Mock 주석은 관련된 객체를 조롱합니다.

@InjectMocks주석은에 의해 생성 된 다른 (및 관련된) 모형을 기본 객체에 주입 할 수 있습니다 @Mock.

둘 다 상호 보완 적입니다.


1
동일한 객체에서 함께 사용할 수 있습니까?
IgorGanapolsky

1
요구 사항에 대한 간단한 예가 있습니까?
Mik378

Mockito Spy를 통해 감시 해야하는 클래스가 있으며이 클래스에는 생성자가 있습니다. 그래서 나는 @InjectMocks이 클래스를 구성하고 그것을 감시하기 위해 사용 하려고 생각하고있었습니다 .
IgorGanapolsky


23
  • @Mock 은 필요한 클래스에 대한 모의 구현을 만듭니다.
  • @InjectMock 은 클래스의 인스턴스를 만들고 @Mock 주석이 표시된 모의 객체를 주입 합니다.

예를 들어

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

여기에는 서비스 클래스에 대한 DAO 클래스가 필요합니다. 그래서 우리는 그것을 조롱하고 서비스 클래스 인스턴스에 주입합니다. 마찬가지로 Spring 프레임 워크에서 모든 @Autowired Bean은 jUnits의 @Mock 에 의해 조롱되고 @InjectMocks를 통해 Bean에 주입 될 수 있습니다.

MockitoAnnotations.initMocks(this)메소드는 이러한 모의를 초기화하고 모든 테스트 메소드에 대해이를 주입하므로 setUp()메소드 에서 호출해야합니다 .

이 링크에는 Mockito 프레임 워크에 대한 유용한 자습서가 있습니다.


13

Mockito의 기반 인 "mocking framework"은 Mock 객체를 생성 할 수있는 기능을 제공하는 프레임 워크입니다. 객체는 코드가 의존하는 실제 객체를 모방하는 데 사용되며 모의 프레임 워크를 사용하여 프록시 객체를 만듭니다. 테스트에서 모의 ​​객체를 사용하면 기본 단위 테스트에서 통합 테스트로 이동합니다.

Mockito는 MIT 라이센스에 따라 릴리스 된 Java 용 오픈 소스 테스트 프레임 워크이며, "모의 프레임 워크"로, 깨끗하고 간단한 API로 아름다운 테스트를 작성할 수 있습니다. Java 공간에는 여러 가지 조롱 프레임 워크가 있지만 기본적으로 두 가지 주요 유형의 모의 객체 프레임 워크가 있습니다. 하나는 프록시를 통해 구현되고 다른 하나는 클래스 리매핑을 통해 구현됩니다.

Spring과 같은 의존성 주입 프레임 워크를 사용하면 코드를 수정하지 않고 프록시 객체를 주입 할 수 있으며 모의 객체는 특정 메소드가 호출 될 것으로 예상하며 예상 결과를 반환합니다.

@InjectMocks주석은 주석 테스트 객체 인스턴스를 분사 필드의 인스턴스를 시도 @Mock하거나 @Spy테스트 객체의 private 필드에 있습니다.

MockitoAnnotations.initMocks(this)호출, 테스트 객체를 재설정하고 모의 객체를 다시 초기화합니다. 따라서 @Before/ @BeforeMethod주석에 보관하십시오.


2
"테스트에서 모의 ​​객체를 사용함으로써 기본 단위 테스트에서 통합 테스트로 넘어갈 수 있습니다." 나를 위해, 조롱은 단위 테스트를 위해 테스트 할 고정 장치를 분리하는 것입니다. 통합 테스트는 실제 조롱되지 않은 종속성을 사용합니다.
WesternGun

10

@Tom에서 언급 한 접근 방식의 이점 중 하나는 SomeManager에서 생성자를 만들 필요가 없으므로 클라이언트가 인스턴스화하도록 제한한다는 것입니다.

@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {

    @InjectMocks
    private SomeManager someManager;

    @Mock
    private SomeDependency someDependency; // this will be injected into someManager

    //You don't need to instantiate the SomeManager with default contructor at all
   //SomeManager someManager = new SomeManager();    
   //Or SomeManager someManager = new SomeManager(someDependency);

     //tests...

}

모범 사례는 응용 프로그램 디자인에 따라 다릅니다.


someManager에 3 개의 다른 생성자가 있으면 어떻게 사용해야하는지 어떻게 알 수 있습니까?
j2emanue 2013

그런 다음 조롱하지 않은 someManager에서 물건을 어떻게 확인 합니까?
IgorGanapolsky


4

@Mock종속 Bean의 참조를 선언 / 모의하는 @InjectMocks데 사용되는 반면 테스트가 작성되는 Bean을 모의하는 데 사용됩니다.

예를 들면 다음과 같습니다.

public class A{

   public class B b;

   public void doSomething(){

   }

}

수업 테스트 A:

public class TestClassA{

   @Mocks
   public class B b;

   @InjectMocks
   public class A a;

   @Test
   public testDoSomething(){

   }

}

4

@InjectMocks 어노테이션을 사용하여 모의 필드를 테스트 오브젝트에 자동으로 주입 할 수 있습니다.

아래 예제에서 @InjectMocks는 mock dataMap을 dataLibrary에 주입하는 데 사용되었습니다.

@Mock
Map<String, String> dataMap ;

@InjectMocks
DataLibrary dataLibrary = new DataLibrary();


    @Test
    public void whenUseInjectMocksAnnotation_() {
        Mockito.when(dataMap .get("aData")).thenReturn("aMeaning");

        assertEquals("aMeaning", dataLibrary .getMeaning("aData"));
    }

3

것을 알 수 있다고 @InjectMocks할 수하려고 사용되지

Mockito 3/4에서 @InjectMocks를 더 이상 사용하지 않고 제거 예약

@avp 답변을 따르고 다음 을 링크로 연결할 수 있습니다.

필드를 자동 와이어 링하기 위해 InjectMocks 주석을 사용하지 않아야하는 이유


3

위의 답변이 다루어졌지만 방금 누락 된 세부 사항을 추가하려고했습니다. 그들 뒤에 이유 (왜).

여기에 이미지 설명을 입력하십시오


삽화:

Sample.java
---------------
    public class Sample{
        DependencyOne dependencyOne;
        DependencyTwo dependencyTwo;


        public SampleResponse methodOfSample(){
            dependencyOne.methodOne();
            dependencyTwo.methodTwo();

            ...

            return sampleResponse;
        }
    }

SampleTest.java
-----------------------
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class})
public class SampleTest{

    @InjectMocks
    Sample sample;

    @Mock
    DependencyOne dependencyOne;

    @Mock
    DependencyTwo dependencyTwo;

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

    public void sampleMethod1_Test(){
        //Arrange the dependencies
        DependencyResponse dependencyOneResponse = Mock(sampleResponse.class);
        Mockito.doReturn(dependencyOneResponse).when(dependencyOne).methodOne();

        DependencyResponse dependencyTwoResponse = Mock(sampleResponse.class);
        Mockito.doReturn(dependencyOneResponse).when(dependencyTwo).methodTwo();

        //call the method to be tested
        SampleResponse sampleResponse = sample.methodOfSample() 

        //Assert
        <assert the SampleResponse here>
    }
}

참고

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