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

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

Ответ 1

@Mock создает насмешку. @InjectMocks создает экземпляр класса и внедряет @Mock созданные с @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

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

Ответ 3

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

@InjectMocks
private SomeManager someManager;

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

@Mock
private SomeDependency someDependency;

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

Ответ 4

@Mock аннотирование mocks связанного объекта.

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

Оба являются взаимодополняющими.

Ответ 5

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

Например

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

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

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

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

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

Ответ 6

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

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

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

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

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

Ответ 7

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

}

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

Ответ 8

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

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

Ответ 9

Обратите внимание, что @InjectMocks устарела

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

и вы можете следить за ответом @avp и ссылаться на:

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

Ответ 10

@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(){

   }

}

Ответ 11

Аннотация @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"));
    }