web-dev-qa-db-de.com

Unterschied zwischen @Mock und @InjectMocks

Was ist der Unterschied zwischen @Mock und @InjectMocks im Mockito-Framework?

318
user2249972

@Mock erstellt einen Schein. @InjectMocks erstellt eine Instanz der Klasse und fügt die mit der Annotation @Mock (oder @Spy) erstellten Mocks in diese Instanz ein. 

Beachten Sie, dass Sie @RunWith(MockitoJUnitRunner.class) oder Mockito.initMocks(this) verwenden müssen, um diese Mocks zu initialisieren und sie zu injizieren.

@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {

    @InjectMocks
    private SomeManager someManager;

    @Mock
    private SomeDependency someDependency; // this will be injected into someManager

     //tests...

}
391
Tom Verelst

Dies ist ein Beispielcode für die Funktionsweise von @Mock und @InjectMocks.

Angenommen, wir haben die Klasse Game und 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;
    }
}

Wie Sie sehen, benötigt Game class Player, um eine attack auszuführen.

@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 verspottet eine Player-Klasse und ihr Verhalten mithilfe der when- und thenReturn-Methode. Mit @InjectMocks setzt Mockito die Player in Game

Beachten Sie, dass Sie nicht einmal ein new Game-Objekt erstellen müssen. Mockito wird es für Sie spritzen.

// you don't have to do this
Game game = new Game(player);

Das gleiche Verhalten erhalten wir auch mit @Spy Annotation. 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 den Type Signature der Game-Klasse überprüft, nämlich Player und List<String>

89
aldok

In Ihrer Testklasse sollte die getestete Klasse mit @InjectMocks kommentiert werden. 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 SomeManager , durch Mocks ersetzt werden:

@Mock
private SomeDependency someDependency;

In diesem Beispiel wird "SomeDependency" in der SomeManager-Klasse verspottet.

64
user2989087

@Mock-Annotation spottet das betroffene Objekt.

@InjectMocks-Annotation ermöglicht das Einfügen der verschiedenen (und relevanten) Mocks, die von @Mock erstellt wurden, in das zugrunde liegende Objekt.

Beide ergänzen sich.

47
Mik378
  • @Mock erstellt eine Scheinimplementierung für die von Ihnen benötigten Klassen.
  • @InjectMock erstellt eine Instanz der Klasse und fügt die mit der Anmerkung @Mock markierten Mocks hinzu.

Zum Beispiel

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

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

Hier brauchen wir die Dao-Klasse für die Serviceklasse. Also spottet man es und injiziert es in die Service-Class-Instanz . Ebenso können alle @Autowired-Beans im Spring-Framework von @Mock in jUnits verspottet und über @InjectMocks in Ihre Bean injiziert werden.

Die MockitoAnnotations.initMocks (diese) Methode initialisiert diese Mocks und injiziert sie für jede Testmethode, sodass sie in der setUp-Methode aufgerufen werden muss.

Dieser Link hat ein gutes Tutorial für Mockito Framework

14
Sana Jahan

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 arbeiten) 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 Mock-Objekten in Ihren Tests wechseln Sie im Wesentlichen vom normalen Unit-Test 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 mit sauberer und einfacher API schöne Tests schreiben können. Es gibt viele verschiedene Mocking-Frameworks im Java-Bereich, jedoch gibt es im Wesentlichen zwei Haupttypen von Mock-Objekt-Frameworks, solche, die über einen Proxy implementiert werden, und solche, die über die Klassenumbildung implementiert werden.

Abhängigkeitsinjektions-Frameworks wie Spring ermöglichen das Einfügen Ihrer Proxy-Objekte, ohne Code zu ändern. Das Mock-Objekt erwartet, dass eine bestimmte Methode aufgerufen wird, und liefert ein erwartetes Ergebnis.

Die Annotation @InjectMocks versucht, die Instanz des Testobjekts zu instanziieren, und fügt mit @Mock oder @Spy kommentierte Felder in private Felder des Testobjekts ein.

MockitoAnnotations.initMocks(this) call, setzt das Prüfobjekt zurück und initialisiert Mocks neu. Denken Sie also daran, dies an Ihrer Annotation @Before/@BeforeMethod zu haben.

12
serup

Ein Vorteil, den Sie mit dem von @Tom genannten Ansatz erhalten, besteht darin, dass Sie im SomeManager keine Konstruktoren erstellen müssen und die Clients daher auf die Instanziierung beschränkt sind. 

@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 es sich um eine bewährte Methode handelt, hängt von Ihrem Anwendungsdesign ab.

6
tintin

Viele Leute haben hier eine gute Erklärung über @Mock vs @InjectMocks gegeben. Ich mag es, aber ich denke, unsere Tests und Anwendungen sollten so geschrieben sein, dass wir @InjectMocks nicht brauchen sollten.

Referenz zum weiteren Lesen mit Beispielen: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/

2
avp

@Mock wird verwendet, um die Referenzen der abhängigen Beans zu deklarieren/zu simulieren, während @InjectMocks verwendet wird, um die Bean zu simulieren, für die der Test erstellt wird.

Zum Beispiel:

public class A{

   public class B b;

   public void doSomething(){

   }

}

test für Klasse A:

public class TestClassA{

   @Mocks
   public class B b;

   @InjectMocks
   public class A a;

   @Test
   public testDoSomething(){

   }

}
1
dev_2014

Mit der @InjectMocks-Annotation können Scheinfelder automatisch in ein Testobjekt eingefügt werden.

Im folgenden Beispiel hat @InjectMocks verwendet, um die nachgebildete dataMap in die dataLibrary zu injizieren.

@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"));
    }
1

Beachten Sie, dass @InjectMocks gerade dabei ist, nicht mehr empfohlen zu werden

deprecate @InjectMocks und Zeitplan für die Entfernung in Mockito 3/4

und du kannst @avp antworten und verlinken weiter folgen: 

Warum sollten Sie InjectMocks-Annotation nicht für automatische Felder verwenden?

0
user7294900