Mockito: Sahte özel alan başlatma


105

Satır içi olarak başlatılan bir alan değişkenini nasıl taklit edebilirim?

class Test {
    private Person person = new Person();
    ...
    public void testMethod() {
        person.someMethod();
        ...
    }
}

Burada , değişkenin başlatılmasıyla alay etmem gereken yöntemi person.someMethod()test ederken alay etmek istiyorum . Bir ipucu?Test.testMethod()person

Düzenleme: Kişi sınıfını değiştirmeme izin verilmiyor.


1
Bu bağlantı size yardımcı olabilir stackoverflow.com/questions/13645571/…
Popeye

2
Kodunuzu yeniden düzenlemelisiniz, böylece bir alay yapabilmelisiniz Person. Seçenekler, bunu yapmak için bir kurucu eklemeyi veya bir ayarlayıcı yöntemi eklemeyi içerir.
Tim Biegeleisen

Yanıtlar:


113

Mockito, size biraz yansıma kazan plakası kodunu kurtarmak için yardımcı bir sınıfla birlikte gelir:

import org.mockito.internal.util.reflection.Whitebox;

//...

@Mock
private Person mockedPerson;
private Test underTest;

// ...

@Test
public void testMethod() {
    Whitebox.setInternalState(underTest, "person", mockedPerson);
    // ...
}

Güncelleme: Maalesef, mockito ekibi Mockito 2'deki sınıfı kaldırmaya karar verdi . Böylece kendi yansıma ortak kodunuzu yazmaya geri döndünüz, başka bir kitaplık (örneğin Apache Commons Lang ) kullanın veya sadece Whitebox sınıfını ( MIT lisanslıdır ) çalın .

Güncelleme 2: JUnit 5, yararlı olabilecek ve sizi başka bir kitaplığa çekmekten kurtarabilecek kendi ReflectionSupport ve AnnotationSupport sınıflarıyla birlikte gelir .


Hedef nesnemi başka nedenlerden dolayı gözetliyorum ve bu durumda nesnem casus olduğunda iç durumu bu şekilde ayarlayamıyorum.
Arun

Neden olmasın? Casuslarla kullanıyorum. Bir Person örneği oluşturun. Saplama gerektiren her şeyi saplayın, ardından Test örneğinizde ayarlayın.
Ralf

Uyarı: Whitebox internalpakette ve Mockito 2.6.2'de artık çalışmıyor gibi görünüyor.
Nova

FieldSetter.setField () kullanabilirsiniz. Aşağıda bunun için bir örnek verdim.
Raj Kumar

1
@Ralf Çünkü Java'da bir referans adını değiştirmek her zaman bir derleme hatasıyla sonuçlanmalıdır.
Joe Coder

78

Partiye oldukça geç kaldım ama burada vuruldum ve bir arkadaşımdan yardım aldım. Önemli olan PowerMock'u kullanmak değildi. Bu, Mockito'nun en son sürümüyle çalışır.

Mockito bununla birlikte geliyor org.mockito.internal.util.reflection.FieldSetter.

Temelde yaptığı şey, yansımayı kullanarak özel alanları değiştirmenize yardımcı olmaktır.

Bunu nasıl kullanıyorsun:

@Mock
private Person mockedPerson;
private Test underTest;

// ...

@Test
public void testMethod() {
    FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);
    // ...
    verify(mockedPerson).someMethod();
}

Bu şekilde sahte bir nesneyi iletebilir ve daha sonra doğrulayabilirsiniz.

İşte referans.


1
FieldSetterMockito 2.x'te artık mevcut değil.
Ralf

5
@Ralf Mockito-core-2.15.0 sürümünü kullanıyorum. Orada mevcuttur. static.javadoc.io/org.mockito/mockito-core/2.0.15-beta/org/… . Yine de beta.
Raj Kumar

1
@RajKumar Class#getDeclaredFieldtek bir parametreyi kabul eder, bu nedenle parenlerin böyle görünmesi gerekir FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);. Bu şekilde yanlış anladım ve örneğinizde düzeltmenin iyi bir fikir olabileceğini düşündüm. Cevabınız için teşekkürler.
Dapeng Li

1
dahili API kullanmak en iyi fikir değil
David

@RajKumar Nice, ancak Zimbo Rodger'ın bahsettiği gibi: Dahili bir API kullanmak iyi bir fikir mi? Neden akut olarak içseldir? Test için çok kullanışlıdır.
Willi Mentzel

38

Bahar Testini kullanmanız durumunda org.springframework.test.util.ReflectionTestUtils'i deneyin.

 ReflectionTestUtils.setField(testObject, "person", mockedPerson);

1
Harika! Bu makaleye bağlantı vermek ve belki de ondan ihtiyaç duyulan bağımlılıkları eklemek yardımcı olabilir: baeldung.com/spring-reflection-test-utils
Willi Mentzel

build.gradle.kts:testImplementation("org.springframework:spring-test:5.1.2.RELEASE")
Willi Mentzel

30

Buraya göndermeyi unuttuğum bu sorunun çözümünü zaten buldum.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Test.class })
public class SampleTest {

@Mock
Person person;

@Test
public void testPrintName() throws Exception {
    PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
    Test test= new Test();
    test.testMethod();
    }
}

Bu çözümün temel noktaları şunlardır:

  1. Test durumlarımı PowerMockRunner ile çalıştırma: @RunWith(PowerMockRunner.class)

  2. Powermock'a Test.classözel alanların manipülasyonuna hazırlanmasını söyleyin :@PrepareForTest({ Test.class })

  3. Ve son olarak, Kişi sınıfının kurucusuyla alay edin:

    PowerMockito.mockStatic(Person.class); PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);


9
Açıklamanız mockStaticişlevden bahsediyor , ancak bu, kod örneğinizde gösterilmiyor. Kod örneğinde mockStaticçağrı olmalı mı , yoksa bu kurucular için gerekli değil mi?
Shadoninja

10

Aşağıdaki kod, REST istemci taklidinde eşleyiciyi başlatmak için kullanılabilir. mapperAlan özel ve birim test kurulumu sırasında ayarlanması gerekir.

import org.mockito.internal.util.reflection.FieldSetter;

new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());

5

@ Jarda'nın kılavuzunu kullanarak, değişkeni tüm testler için aynı değere ayarlamanız gerekiyorsa bunu tanımlayabilirsiniz:

@Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
    FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}

Ancak özel değerlerin farklı olması konusunda dikkatli olunması gerektiğine dikkat edin. Özel iseler, bir sebepten ötürü.

Örneğin, birim testlerinde bir uykunun bekleme süresini değiştirmek için kullanıyorum. Gerçek örneklerde 10 saniye uyumak istiyorum ama birim testte hemen olursa memnunum. Entegrasyon testlerinde gerçek değeri test etmelisiniz.

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.