Mockito çerçevesinde @Mockve @InjectMocksarasındaki fark nedir ?
Mockito çerçevesinde @Mockve @InjectMocksarasındaki fark nedir ?
Yanıtlar:
@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...
}
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>.
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.
@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.
@InjectMocksbu sınıfı inşa etmek ve onu gözetlemek için kullanmayı düşünüyordum.
Ö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
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.
@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.
Birçok kişi burada @Mockvs hakkında büyük bir açıklama yaptı @InjectMocks. Sevdim, ama sanırım testlerimiz ve uygulamamız, kullanmamız gerekmeyecek şekilde yazılmalıdır @InjectMocks.
Örneklerle daha fazla okuma için referans: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/
@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(){
}
}
@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"));
}
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?
Yukarıdaki cevaplar kapsanmış olsa da, sadece eksik gördüğüm dakika detaylarını eklemeye çalıştım. Arkalarındaki sebep (Neden).
İ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>
}
}