it-swarm.com.ru

Разница между @Mock и @InjectMocks

В чем разница между @Mock и @InjectMocks в среде Mockito?

318
user2249972

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

}
391
Tom Verelst

Это пример кода о том, как работают @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. Мокито сделает это за тебя.

// 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 класса Game, а это Player и List<String>

89
aldok

В вашем тестовом классе тестируемый класс должен быть аннотирован @InjectMocks. Это говорит Mockito, в какой класс вводить макеты:

@InjectMocks
private SomeManager someManager;

С этого момента мы можем указать, какие конкретные методы или объекты внутри класса, в этом случае SomeManager , будут заменены на mocks:

@Mock
private SomeDependency someDependency;

В этом примере SomeDependency внутри класса SomeManager будет подвергнут ложной проверке.

64
user2989087

@Mock аннотация пересмеивает соответствующий объект.

Аннотация @InjectMocks позволяет внедрить в базовый объект различные (и релевантные) макеты, созданные @Mock.

Оба дополняют друг друга.

47
Mik378
  • @Mock создает фиктивную реализацию для нужных вам классов.
  • @InjectMock создает экземпляр класса и внедряет в него макеты, помеченные аннотациями @Mock.

Например

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

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

Здесь нам нужен класс dao для класса обслуживания. Итак, мы имитируем это и внедряем его в экземпляр класса обслуживания Аналогично, в среде Spring все компоненты bean @Autowired могут быть смоделированы @Mock в jUnits и внедрены в ваш компонент через @InjectMocks.

Метод MockitoAnnotations.initMocks (this) инициализирует эти макеты и внедряет их для каждого метода тестирования, поэтому его необходимо вызывать в методе setUp.

Эта ссылка имеет хороший учебник для платформы Mockito

14
Sana Jahan

«Среда Mocking», на которой основан Mockito, - это среда, которая дает вам возможность создавать объекты Mock (в старых терминах эти объекты можно называть шунтами, поскольку они работают как шунты для зависимой функциональности) Другими словами фиктивный объект используется для имитации реального объекта, от которого зависит ваш код, вы создаете прокси-объект с фальшивой структурой . Используя фиктивные объекты в своих тестах, вы по сути переходите от обычного модульного тестирования к интеграционному тестированию.

Mockito - это инфраструктура тестирования с открытым исходным кодом для Java, выпущенная по лицензии MIT, это «среда для моделирования», которая позволяет вам писать красивые тесты с чистым и простым API. В пространстве Java существует множество различных фреймворков, однако, по сути, существует два основных типа фреймворков для фиктивных объектов: те, которые реализуются через прокси, и те, которые реализуются через переназначение классов.

Среды внедрения зависимостей, такие как Spring, позволяют внедрять прокси-объекты без изменения какого-либо кода, фиктивный объект ожидает вызова определенного метода и возвращает ожидаемый результат.

Аннотация @InjectMocks пытается создать экземпляр экземпляра объекта тестирования и внедряет поля, отмеченные @Mock или @Spy, в частные поля объекта тестирования.

Вызов MockitoAnnotations.initMocks(this) сбрасывает объект тестирования и повторно инициализирует макеты, поэтому не забудьте указать это в аннотации @Before/@BeforeMethod.

12
serup

Одно из преимуществ, которое вы получаете с подходом, упомянутым @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...

}

Хорошая практика или нет, зависит от вашего дизайна приложения.

6
tintin

Многие люди дали здесь отличное объяснение о @Mock против @InjectMocks. Мне это нравится, но я думаю, что наши тесты и приложения должны быть написаны таким образом, чтобы нам не нужно было использовать @InjectMocks.

Ссылка для дальнейшего чтения с примерами: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/

2
avp

@Mock используется для объявления/макета ссылок зависимых bean-компонентов, в то время как @InjectMocks используется для макета bean-компонента, для которого создается тест.

Например:

public class A{

   public class B b;

   public void doSomething(){

   }

}

тест для класса А:

public class TestClassA{

   @Mocks
   public class B b;

   @InjectMocks
   public class A a;

   @Test
   public testDoSomething(){

   }

}
1
dev_2014

Аннотация @InjectMocks может использоваться для автоматической вставки фиктивных полей в тестовый объект.

В приведенном ниже примере @InjectMocks использовал для вставки фиктивного 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"));
    }
1
Lahiru Wijesekara

Обратите внимание, что этот @InjectMocks собирается быть устаревшим

устареть @InjectMocks и график удаления в Mockito 3/4

и вы можете подписаться на @avp answer и ссылку на: 

Почему вы не должны использовать аннотацию InjectMocks для автоматического переноса полей

0
user7294900