@Mock和@InjectMocks之间的区别

@Mock@InjectMocks在Mockito框架中有什么区别?

@Mock创build一个模拟。 @InjectMocks创build该类的一个实例,并将用@Mock (或@Spy )注释创build的@Spy注入到该实例中。 请注意,您必须使用@RunWith(MockitoJUnitRunner.class)Mockito.initMocks(this)来初始化这些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注解允许向底层对象注入由@Mock创build的不同(和相关的) @Mock

两者都是互补的。

在你的testing类中,被testing的类应该用@InjectMocks注释。 这告诉Mockito哪个类注入模拟:

 @InjectMocks private SomeManager someManager; 

从此,我们可以指定类中的哪些特定方法或对象,在这种情况下, SomeManager将被mocksreplace:

 @Mock private SomeDependency someDependency; 

在这个例子中,SomeManager类中的SomeDependency将被模拟。

Mockito基于的一个“嘲讽框架”是一个框架,它使您能够创buildMock对象(从旧的angular度来说,这些对象可以被称为分stream器,因为它们作为依赖function的分stream器)换句话说,模拟对象是用来模仿你的代码所依赖的真实对象的,你用嘲笑框架创build一个代理对象。 通过在testing中使用模拟对象,您基本上可以从正常的unit testing转换到集成testing

Mockito是在MIT许可证下发布的Java开源testing框架,它是一个“嘲讽框架”,它可以让你使用干净而简单的API编写漂亮的testing。 Java空间中有许多不同的模拟框架,但基本上有两种主要types的模拟对象框架,一种是通过代理实现的,另一种是通过类重新映射实现的。

像Spring这样的dependency injection框架允许你在不修改任何代码的情况下注入你的代理对象,模拟对象需要调用某个方法,它会返回一个预期的结果。

@InjectMocks注解试图实例化testing对象实例,并将注解为@Mock@Spy字段@Spy到testing对象的专用字段中。

MockitoAnnotations.initMocks(this)调用,重置testing对象并重新初始化mock,所以记得在你的@Before / @BeforeMethod注解中有这个。

我将向您展示一个关于@Mock@InjectMocks如何工作的示例代码。

假设我们有Game and 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类,它的行为使用whenthenReturn方法。 最后,使用@InjectMocks Mockito将该Player放入Game

注意你甚至不需要创build一个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会检查Game类的Type Signature ,它是PlayerList<String>

我希望清除一些混乱。

用@Tom提到的方法获得的一个优点是,您不必在SomeManager中创build任何构造函数,因此限制客户端实例化它。

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

这是否是一个好的做法取决于你的应用程序devise。