Was ist der Unterschied zwischen @Mockund @InjectMocksim Mockito-Framework?
Was ist der Unterschied zwischen @Mockund @InjectMocksim Mockito-Framework?
Antworten:
@Mockschafft einen Schein. @InjectMocksErstellt eine Instanz der Klasse und fügt die mit den @Mock(oder @Spy) Annotationen erstellten Mocks in diese Instanz ein.
Beachten Sie, dass Sie diese Mocks verwenden @RunWith(MockitoJUnitRunner.class)oder Mockito.initMocks(this)initialisieren und injizieren müssen.
@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {
@InjectMocks
private SomeManager someManager;
@Mock
private SomeDependency someDependency; // this will be injected into someManager
//tests...
}
Dies ist ein Beispielcode, wie @Mockund @InjectMocksfunktioniert.
Sagen wir, wir haben Gameund PlayerKlasse.
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;
}
}
Wie Sie sehen, muss die GameKlasse eine Playerausführen 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 wird eine Spielerklasse verspotten und ihr Verhalten mit whenund thenReturnMethode. Schließlich verwendet @InjectMockswird Mockito setzen , dass Playerin Game.
Beachten Sie, dass Sie nicht einmal ein new GameObjekt erstellen müssen . Mockito wird es für Sie injizieren.
// you don't have to do this
Game game = new Game(player);
Wir werden das gleiche Verhalten auch mit @SpyAnmerkungen erhalten. Auch wenn der Attributname unterschiedlich ist.
@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();
}
// ...
Das liegt daran, dass Mockito die Type Signatureof Game-Klasse überprüft , die Playerund ist List<String>.
In Ihrer Testklasse sollte die getestete Klasse mit Anmerkungen versehen sein @InjectMocks. Dies teilt Mockito mit, in welche Klasse Mocks injiziert werden sollen:
@InjectMocks
private SomeManager someManager;
Von da an können wir angeben, welche spezifischen Methoden oder Objekte innerhalb der Klasse in diesem Fall SomeManagerdurch Mocks ersetzt werden sollen:
@Mock
private SomeDependency someDependency;
In diesem Beispiel wird SomeDependencyinnerhalb der SomeManagerKlasse verspottet.
@Mock Annotation verspottet das betroffene Objekt.
@InjectMocksMit Annotation können die verschiedenen (und relevanten) Mocks, die von erstellt wurden, in das zugrunde liegende Objekt eingefügt werden @Mock.
Beide ergänzen sich.
@InjectMocks, diese Klasse zu konstruieren und sie auch auszuspionieren.
Zum Beispiel
@Mock
StudentDao studentDao;
@InjectMocks
StudentService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
Hier benötigen wir die DAO-Klasse für die Serviceklasse. Also verspotten wir es und fügen es in die Serviceklasseninstanz ein. In ähnlicher Weise können im Spring-Framework alle @ Autowired- Beans verspottet werden @Mock in jUnits @InjectMocks in Ihre Bean injiziert werden.
MockitoAnnotations.initMocks(this) Die Methode initialisiert diese Mocks und injiziert sie für jede Testmethode, sodass sie in der aufgerufen werden muss setUp() Methode werden muss.
Dieser Link enthält ein gutes Tutorial für das Mockito-Framework
Ein "Mocking Framework", auf dem Mockito basiert, ist ein Framework, mit dem Sie Mock-Objekte erstellen können (in alten Begriffen könnten diese Objekte Shunts genannt werden, da sie als Shunts für abhängige Funktionen fungieren). Mit anderen Worten, ein Mock Objekt wird verwendet, um das reale Objekt zu imitieren, von dem Ihr Code abhängig ist. Sie erstellen ein Proxy-Objekt mit dem Mocking-Framework. Durch die Verwendung von Scheinobjekten in Ihren Tests wechseln Sie im Wesentlichen vom normalen Komponententest zum Integrationstest
Mockito ist ein Open-Source-Testframework für Java, das unter der MIT-Lizenz veröffentlicht wurde. Es ist ein "Mocking-Framework", mit dem Sie schöne Tests mit einer sauberen und einfachen API schreiben können. Es gibt viele verschiedene Mocking-Frameworks im Java-Bereich, es gibt jedoch im Wesentlichen zwei Haupttypen von Mock-Objekt-Frameworks, solche, die über Proxy implementiert werden, und solche, die über Klassen-Remapping implementiert werden.
Abhängigkeitsinjektions-Frameworks wie Spring ermöglichen es Ihnen, Ihre Proxy-Objekte zu injizieren, ohne Code zu ändern. Das Mock-Objekt erwartet, dass eine bestimmte Methode aufgerufen wird, und gibt ein erwartetes Ergebnis zurück.
Die @InjectMocksAnnotation versucht, die Testobjektinstanz zu instanziieren und fügt mit @Mockoder @Spyin private Felder des Testobjekts annotierte Felder ein.
MockitoAnnotations.initMocks(this)Rufen Sie auf, setzen Sie das Testobjekt zurück und initialisieren Sie die Mocks neu. Denken Sie also daran, dies bei Ihrer @Before/ @BeforeMethodAnnotation zu haben.
Ein Vorteil des von @Tom erwähnten Ansatzes besteht darin, dass Sie im SomeManager keine Konstruktoren erstellen müssen und somit die Clients einschränken müssen, um ihn zu instanziieren.
@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...
}
Ob dies eine gute Vorgehensweise ist oder nicht, hängt von Ihrem Anwendungsdesign ab.
Viele Leute haben hier eine großartige Erklärung über @Mockvs gegeben @InjectMocks. Ich mag es, aber ich denke, unsere Tests und Anwendungen sollten so geschrieben sein, dass wir sie nicht brauchen sollten@InjectMocks .
Referenz zum weiteren Lesen mit Beispielen: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/
@Mockwird verwendet, um die Referenzen der abhängigen Beans zu deklarieren / zu verspotten, während @InjectMocksdie Bean verspottet wird, für die ein Test erstellt wird.
Zum Beispiel:
public class A{
public class B b;
public void doSomething(){
}
}
Test für die Klasse A:
public class TestClassA{
@Mocks
public class B b;
@InjectMocks
public class A a;
@Test
public testDoSomething(){
}
}
Die Annotation @InjectMocks kann verwendet werden, um Scheinfelder automatisch in ein Testobjekt einzufügen.
Im folgenden Beispiel hat @InjectMocks verwendet, um die nachgebildete dataMap in die dataLibrary einzufügen.
@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"));
}
Beachten Sie, dass @InjectMocksdies bald veraltet sein wird
Verwerfen Sie @InjectMocks und planen Sie das Entfernen in Mockito 3/4
und Sie können @avp Antwort folgen und auf verlinken :
Warum Sie InjectMocks Annotation nicht für Autowire-Felder verwenden sollten
Obwohl die obigen Antworten behandelt wurden, habe ich nur versucht, kleinste Details hinzuzufügen, die mir fehlen. Der Grund dahinter (The Why).
Illustration:
Sample.java
---------------
public class Sample{
DependencyOne dependencyOne;
DependencyTwo dependencyTwo;
public SampleResponse methodOfSample(){
dependencyOne.methodOne();
dependencyTwo.methodTwo();
...
return sampleResponse;
}
}
SampleTest.java
-----------------------
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class})
public class SampleTest{
@InjectMocks
Sample sample;
@Mock
DependencyOne dependencyOne;
@Mock
DependencyTwo dependencyTwo;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
public void sampleMethod1_Test(){
//Arrange the dependencies
DependencyResponse dependencyOneResponse = Mock(sampleResponse.class);
Mockito.doReturn(dependencyOneResponse).when(dependencyOne).methodOne();
DependencyResponse dependencyTwoResponse = Mock(sampleResponse.class);
Mockito.doReturn(dependencyOneResponse).when(dependencyTwo).methodTwo();
//call the method to be tested
SampleResponse sampleResponse = sample.methodOfSample()
//Assert
<assert the SampleResponse here>
}
}