Mockito 프레임 워크 @Mock
와 @InjectMocks
Mockito 프레임 워크 의 차이점은 무엇입니까 ?
Mockito 프레임 워크 @Mock
와 @InjectMocks
Mockito 프레임 워크 의 차이점은 무엇입니까 ?
답변:
@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...
}
이것은 어떻게 @Mock
그리고 @InjectMocks
작동 하는지에 대한 샘플 코드입니다 .
우리가 말 Game
과 Player
클래스입니다.
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 클래스를 조롱하고 사용 when
및 thenReturn
메소드 동작 입니다. 마지막으로, 사용 @InjectMocks
Mockito하면 해당 넣을 것 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 Signature
가 Player
및 의 게임 클래스를 확인하기 때문 List<String>
입니다.
테스트 클래스에서 테스트 된 클래스에는 주석을 달아야합니다 @InjectMocks
. 이것은 Mockito에게 mock을 주입 할 클래스를 알려줍니다 :
@InjectMocks
private SomeManager someManager;
그런 다음 클래스 내부의 특정 메소드 또는 객체 (이 경우) SomeManager
가 모의 객체로 대체되도록 지정할 수 있습니다.
@Mock
private SomeDependency someDependency;
이 예제에서는 클래스 SomeDependency
내부 SomeManager
가 조롱됩니다.
@Mock
주석은 관련된 객체를 조롱합니다.
@InjectMocks
주석은에 의해 생성 된 다른 (및 관련된) 모형을 기본 객체에 주입 할 수 있습니다 @Mock
.
둘 다 상호 보완 적입니다.
@InjectMocks
이 클래스를 구성하고 그것을 감시하기 위해 사용 하려고 생각하고있었습니다 .
예를 들어
@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의 기반 인 "mocking framework"은 Mock 객체를 생성 할 수있는 기능을 제공하는 프레임 워크입니다. 객체는 코드가 의존하는 실제 객체를 모방하는 데 사용되며 모의 프레임 워크를 사용하여 프록시 객체를 만듭니다. 테스트에서 모의 객체를 사용하면 기본 단위 테스트에서 통합 테스트로 이동합니다.
Mockito는 MIT 라이센스에 따라 릴리스 된 Java 용 오픈 소스 테스트 프레임 워크이며, "모의 프레임 워크"로, 깨끗하고 간단한 API로 아름다운 테스트를 작성할 수 있습니다. Java 공간에는 여러 가지 조롱 프레임 워크가 있지만 기본적으로 두 가지 주요 유형의 모의 객체 프레임 워크가 있습니다. 하나는 프록시를 통해 구현되고 다른 하나는 클래스 리매핑을 통해 구현됩니다.
Spring과 같은 의존성 주입 프레임 워크를 사용하면 코드를 수정하지 않고 프록시 객체를 주입 할 수 있으며 모의 객체는 특정 메소드가 호출 될 것으로 예상하며 예상 결과를 반환합니다.
@InjectMocks
주석은 주석 테스트 객체 인스턴스를 분사 필드의 인스턴스를 시도 @Mock
하거나 @Spy
테스트 객체의 private 필드에 있습니다.
MockitoAnnotations.initMocks(this)
호출, 테스트 객체를 재설정하고 모의 객체를 다시 초기화합니다. 따라서 @Before
/ @BeforeMethod
주석에 보관하십시오.
@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...
}
모범 사례는 응용 프로그램 디자인에 따라 다릅니다.
많은 사람들이 @Mock
vs 에 대해 여기에서 훌륭한 설명을했습니다 @InjectMocks
. 마음에 들지만 테스트와 응용 프로그램을 사용할 필요가없는 방식으로 작성해야한다고 생각합니다 @InjectMocks
.
예제와 함께 더 읽을 참조 : https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/
@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(){
}
}
@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"));
}
것을 알 수 있다고 @InjectMocks
할 수하려고 사용되지
Mockito 3/4에서 @InjectMocks를 더 이상 사용하지 않고 제거 예약
@avp 답변을 따르고 다음 을 링크로 연결할 수 있습니다.
필드를 자동 와이어 링하기 위해 InjectMocks 주석을 사용하지 않아야하는 이유
위의 답변이 다루어졌지만 방금 누락 된 세부 사항을 추가하려고했습니다. 그들 뒤에 이유 (왜).
삽화:
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>
}
}