@Mock ve @InjectMocks arasındaki fark


Yanıtlar:


543

@Mockbir alay yaratır. @InjectMockssınıfın bir örneğini oluşturur ve @Mock(veya @Spy) ek açıklamaları ile oluşturulan alayları bu örneğe enjekte eder .

Bu alayları başlatmak ve enjekte etmek için @RunWith(MockitoJUnitRunner.class)veya kullanmanız gerektiğini unutmayın 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
Kısa ve özlü cevap. Çok yararlı;)
Chaklader Asfak Arefe

Bu geçişli bağımlılıklar için mi yoksa sadece doğrudan üyeler için mi geçerli?
Pierre Thibault

@PierreThibault Enjekte eden alaylar sadece doğrudan üyeler için çalışır, ancak derin saplamalara izin verecek bir alaycı static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/…
Tom

1
Bu online makalenin çoğu daha açık olduğunu hissediyorum .... küçük yorumlar kıçımı kurtarmak ...
IHC_Applroid

@Mock ek açıklama ile bağlam gibi sağlanamayan bazı öğelerim var. Bunu ana sınıf için nasıl sağlayabilirim?
Mehdi

220

Bu nasıl @Mockve nasıl @InjectMocksçalıştığına dair örnek bir koddur .

Elimizdeki Say Gameve Playersınıfı.

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;
    }
}

Gördüğünüz gibi, Gamesınıf Playerbir 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, bir Player sınıfı ile alay edecek ve davranışını whenve thenReturnyöntemini kullanacak . Son olarak, kullanarak @InjectMocksMockito o koyacağız Playeriçine Game.

Bir new Gamenesne oluşturmanız bile gerekmediğine dikkat edin . Mockito sizin için enjekte edecek.

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

@SpyEk açıklama kullanarak da aynı davranışı elde edeceğiz . Özellik adı farklı olsa bile.

@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 kontrol edecek olmasıdır Type Signatureolan Oyun sınıfının Playerve List<String>.


16
Bu örnekle kabul edilen cevap olmalıdır.
AnnaKlein

4
Bence bu da en iyi asnwer
Evgeniy Dorofeev

4
Bu en iyi cevap üçlü olduğunu düşünüyorum.
Harvey Dent

1
Bazen bir sınıf için alaycı ve tasarımı zor olan alay ile test buluyorum. Ancak, bu örnek genel bakış sağlamak için çok yardımcı olur.
Chaklader Asfak Arefe

1
Çok teşekkürler :) Daha iyi bir açıklama ile noktaya.
Rishi

80

Test sınıfınızda, test edilen sınıfa açıklama eklenmelidir @InjectMocks. Bu Mockito'ya alayları hangi sınıfa enjekte edeceğini söyler:

@InjectMocks
private SomeManager someManager;

O andan itibaren, sınıfın içinde hangi belirli yöntemlerin veya nesnelerin, bu durumda, SomeManageralaylarla değiştirileceğini belirtebiliriz :

@Mock
private SomeDependency someDependency;

Bu örnekte, sınıfın SomeDependencyiçinde SomeManageralay edilecektir.


6
someManager'da birden fazla kurucu varsa bu işe yarar mı? someManager'da 5 kurucu varsa, hangisini kullanmak istediğinizi nasıl bilebilir?
j2emanue

51

@Mock ek açıklama ilgili nesneyle alay eder.

@InjectMocksek açıklama, altta yatan nesneye yaratılan farklı (ve ilgili) alayların enjekte edilmesini sağlar @Mock.

Her ikisi de tamamlayıcıdır.


1
Aynı nesne üzerinde birlikte kullanılabilirler mi?
IgorGanapolsky

1
İhtiyacınıza ilişkin bir mini örnek var mı?
Mik378

(Mockito Spy aracılığıyla) casusluk edilmesi gereken bir sınıfım var ve bu sınıfın bir yapıcısı var. Bu yüzden @InjectMocksbu sınıfı inşa etmek ve onu gözetlemek için kullanmayı düşünüyordum.
IgorGanapolsky

1
Aradığın şey bu mu? stackoverflow.com/a/35969166/985949
Mik378

23
  • @Mock , ihtiyacınız olan sınıflar için sahte bir uygulama oluşturur.
  • @InjectMock sınıfın bir örneğini oluşturur ve @Mock ek açıklamaları ile işaretlenmiş alayları bu gruba enjekte eder.

Örneğin

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

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

Burada servis sınıfı için DAO sınıfına ihtiyacımız var. Böylece, bunu alay eder ve hizmet sınıfı örneğine enjekte ederiz. Benzer şekilde, Bahar çerçevesinde tüm @Autowired fasulyeleri jUnits'deki @Mock tarafından alay edilebilir ve @InjectMocks aracılığıyla fasulyenize enjekte edilebilir.

MockitoAnnotations.initMocks(this)yöntemi bu alayları başlatır ve her test yöntemi için bunları enjekte eder, böylece yöntemde çağrılması gerekir setUp().

Bu bağlantı Mockito çerçevesi için iyi bir öğreticiye sahiptir


13

Mockito'nun dayandığı bir "alaycı çerçeve", size Mock nesneleri yaratma yeteneği veren bir çerçevedir (eski terimlerle bu işlevlere bağımlı işlevsellik için şant olarak çalıştıkları için şantlar denilebilir) Başka bir deyişle, alay nesne, kodunuzun bağımlı olduğu gerçek nesneyi taklit etmek için kullanılır, alaycı çerçeveyle bir proxy nesnesi oluşturursunuz. Testlerinizde sahte nesneler kullanarak temelde normal birim testinden entegrasyon testine geçersiniz.

Mockito, MIT Lisansı altında yayınlanan Java için açık kaynaklı bir test çerçevesi, temiz ve basit API ile güzel testler yazmanıza izin veren bir "alaycı çerçeve" dir. Java alanında birçok farklı alaycı çerçeve vardır, ancak temelde iki temel sahte nesne çerçevesi türü vardır, bunlar proxy üzerinden uygulananlar ve sınıf yeniden eşleme yoluyla uygulananlar.

Spring gibi bağımlılık enjeksiyon çerçeveleri, herhangi bir kodu değiştirmeden proxy nesnelerinizi enjekte etmenizi sağlar, sahte nesne çağrılacak belirli bir yöntem bekler ve beklenen bir sonuç döndürür.

@InjectMocksEk açıklama ile açıklamalı test nesne örneği ve enjekte eder alanları örneğini oluşturmaya çalıştığında @Mockveya @Spytest nesnenin özel alanlara.

MockitoAnnotations.initMocks(this)çağrı yapın, test nesnesini sıfırlar ve alayları yeniden başlatır, bu yüzden bunu @Before/ @BeforeMethodek açıklamanızda bulundurmayı unutmayın.


2
"Testlerinizde sahte nesneler kullanarak, temelde normal birim testinden entegrasyon testine geçeceksiniz" demeyeceğim. Benim için alay, birim test için test edilecek armatürü izole etmektir. Entegrasyon testi gerçek alaycı olmayan bağımlılıkları kullanacaktır.
WesternGun

10

@Tom tarafından belirtilen yaklaşımla elde edeceğiniz bir avantaj, SomeManager'da herhangi bir kurucu oluşturmak zorunda kalmamanız ve böylece istemcileri somutlaştırmak için sınırlamanızdır.

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

}

İyi bir uygulama olup olmadığı uygulama tasarımınıza bağlıdır.


someManager'ın 3 farklı kurucusu olsaydı hangisini kullanacağını nasıl bilebilirdi?
j2emanue

Daha sonra alay edilmezse someManager'daki öğeleri nasıl doğrularsınız ?
IgorGanapolsky


4

@Mockbağımlı fasulyenin referanslarını bildirmek / alay etmek @InjectMocksiçin kullanılırken, testin yapıldığı fasulyeyi alay etmek için kullanılır.

Örneğin:

public class A{

   public class B b;

   public void doSomething(){

   }

}

sınıf için test A:

public class TestClassA{

   @Mocks
   public class B b;

   @InjectMocks
   public class A a;

   @Test
   public testDoSomething(){

   }

}

4

@InjectMocks ek açıklaması, sahte alanları otomatik olarak bir test nesnesine enjekte etmek için kullanılabilir.

Aşağıdaki örnekte @InjectMocks, sahte dataMap öğesini dataLibrary'ye enjekte etmek için kullanılmıştır.

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

3

Kullanımdan kaldırılmak@InjectMocks üzere olduğuna dikkat edin

@InjectMocks'u kullanımdan kaldırın ve Mockito 3/4'te kaldırılmak için zamanlama

ve @avp cevabını takip edebilir ve bağlantı kurabilirsiniz :

Alanları Otomatik Aktarma için Neden InjectMocks Ek Açıklama Kullanmamalısınız?


3

Yukarıdaki cevaplar kapsanmış olsa da, sadece eksik gördüğüm dakika detaylarını eklemeye çalıştım. Arkalarındaki sebep (Neden).

resim açıklamasını buraya girin


İllüstrasyon:

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

Referans

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.