@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类,它的行为使用when
和thenReturn
方法。 最后,使用@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
,它是Player
和List<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。