Mockito çerçevesinde @Mock
ve @InjectMocks
arasındaki fark nedir ?
Mockito çerçevesinde @Mock
ve @InjectMocks
arasındaki fark nedir ?
Yanıtlar:
@Mock
bir alay yaratır. @InjectMocks
sı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 @Mock
ve nasıl @InjectMocks
çalıştığına dair örnek bir koddur .
Elimizdeki Say Game
ve Player
sı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, Game
sınıf Player
bir 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ı when
ve thenReturn
yöntemini kullanacak . Son olarak, kullanarak @InjectMocks
Mockito o koyacağız Player
içine Game
.
Bir new Game
nesne 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);
@Spy
Ek 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 Signature
olan Oyun sınıfının Player
ve 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, SomeManager
alaylarla değiştirileceğini belirtebiliriz :
@Mock
private SomeDependency someDependency;
Bu örnekte, sınıfın SomeDependency
içinde SomeManager
alay edilecektir.
@Mock
ek açıklama ilgili nesneyle alay eder.
@InjectMocks
ek açıklama, altta yatan nesneye yaratılan farklı (ve ilgili) alayların enjekte edilmesini sağlar @Mock
.
Her ikisi de tamamlayıcıdır.
@InjectMocks
bu 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.
@InjectMocks
Ek açıklama ile açıklamalı test nesne örneği ve enjekte eder alanları örneğini oluşturmaya çalıştığında @Mock
veya @Spy
test 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
/ @BeforeMethod
ek 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 @Mock
vs 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/
@Mock
bağımlı fasulyenin referanslarını bildirmek / alay etmek @InjectMocks
iç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>
}
}