В чем разница между @Mock
и @InjectMocks
в каркасе Mockito?
Разница между @Mock и @InjectMocks
Ответ 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()
.
Ответ 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"));
}