Mockito'da Bitmemiş Saplama Algılandı


160

Testleri çalıştırırken aşağıdaki istisnayı alıyorum. Mockito'yu alay etmek için kullanıyorum. Mockito kütüphanesi tarafından bahsedilen ipuçları yardımcı olmuyor.

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
    -> at com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355)

    E.g. thenReturn() may be missing.
    Examples of correct stubbing:
        when(mock.isOk()).thenReturn(true);
        when(mock.isOk()).thenThrow(exception);
        doThrow(exception).when(mock).someVoidMethod();
    Hints:
     1. missing thenReturn()
     2. you are trying to stub a final method, you naughty developer!

        at a.b.DomainTestFactory.myTest(DomainTestFactory.java:276)
        ..........

Test Kodu DomainTestFactory. Aşağıdaki testi çalıştırdığımda istisnayı görüyorum.

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); // Line 355
}

private List<SomeModel> getSomeList() {
    SomeModel model = Mockito.mock(SomeModel.class);
    Mockito.when(model.getName()).thenReturn("SomeName"); // Line 276
    Mockito.when(model.getAddress()).thenReturn("Address");
    return Arrays.asList(model);
}

public class SomeModel extends SomeInputModel{
    protected String address;
    protected List<SomeClass> properties;

    public SomeModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    public String getAddress() {
        return this.address;
    }

}

public class SomeInputModel{

    public NetworkInputModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    protected String Name;
    protected List<SomeClass> properties;

    public String getName() {
        return this.Name;
    }

    public void setName(String value) {
        this.Name = value;
    }
}

Merhaba Mureinik, Gönderiyi satır numaralarıyla güncelledim
Royal Rose

Yanıtlar:


382

Alay içinde alay ediyorsun. Sen diyorsun getSomeList()için alaycı bitirmenizden önce, bazı alaycı işlevi gören MyMainModel. Mockito bunu yapmandan hoşlanmaz.

Değiştir

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}

ile

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    List<SomeModel> someModelList = getSomeList();
    Mockito.when(mainModel.getList()).thenReturn(someModelList);
}

Bunun neden bir soruna neden olduğunu anlamak için Mockito'nun nasıl çalıştığı hakkında biraz bilgi sahibi olmanız ve ayrıca Java'da ifadelerin ve ifadelerin hangi sırayla değerlendirildiğinin farkında olmanız gerekir.

Mockito kaynak kodunuzu okuyamaz, bu yüzden ondan ne yapmasını istediğinizi anlamak için statik duruma büyük ölçüde güvenir. Sahte bir nesnede bir yöntemi çağırdığınızda, Mockito, çağrının ayrıntılarını dahili bir çağrı listesine kaydeder. whenYöntem listesinden bu çağrıları içinden geçen okur ve bu çağırma kaydeden OngoingStubbingDöndürdüğü nesne.

Çizgi

Mockito.when(mainModel.getList()).thenReturn(someModelList);

Mockito ile aşağıdaki etkileşimlere neden olur:

  • Mock yöntemi mainModel.getList()denir,
  • Statik yöntem whendenir,
  • Yöntem thenReturn, yöntem OngoingStubbingtarafından döndürülen nesnede çağrılır when.

thenReturnYöntem daha sonra yoluyla alınan mock talimatını OngoingStubbingiçin uygun olan herhangi bir aramayı işlemek için bir yöntem getListdönüş yöntemi someModelList.

Aslında Mockito kodunuzu göremediği için alayınızı şu şekilde de yazabilirsiniz:

mainModel.getList();
Mockito.when((List<SomeModel>)null).thenReturn(someModelList);

Bu stilin okunması biraz daha az nettir, özellikle bu durumda nulldönüştürülmesi gerektiğinden, ancak Mockito ile aynı etkileşim dizisini oluşturur ve yukarıdaki satırla aynı sonucu elde eder.

Ancak, çizgi

Mockito.when(mainModel.getList()).thenReturn(getSomeList());

Mockito ile aşağıdaki etkileşimlere neden olur:

  1. Mock yöntemi mainModel.getList()denir,
  2. Statik yöntem whendenir,
  3. Yeni mockbir SomeModelyaratılır (iç getSomeList()),
  4. Mock yöntemi model.getName()denir,

Bu noktada Mockito'nun kafası karışır. mainModel.getList()Alay ettiğinizi sanıyordu , ama şimdi ona model.getName()yöntemle dalga geçmek istediğinizi söylüyorsunuz . Mockito için aşağıdakileri yaptığınız anlaşılıyor:

when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);

Bu aptalca görünüyor Mockitoçünkü ne yaptığından emin olamıyormainModel.getList() .

thenReturnJVM'nin yöntemi çağırmadan önce bu yöntemin parametrelerini değerlendirmesi gerektiğinden , yöntem çağrısına ulaşamadığımızı unutmayın. Bu durumda bu, getSomeList()yöntemi çağırmak anlamına gelir .

Mockito'nun yaptığı gibi, genellikle statik duruma güvenmek kötü bir tasarım kararıdır, çünkü En Az Şaşkınlık İlkesinin ihlal edildiği durumlara yol açabilir. Bununla birlikte, Mockito'nun tasarımı, bazen şaşkınlığa yol açsa bile, açık ve etkileyici bir alay konusu yapıyor.

Son olarak, Mockito'nun son sürümleri yukarıdaki hata mesajına fazladan bir satır ekler. Bu ekstra satır, bu soruyla aynı durumda olabileceğinizi gösterir:

3: Eğer tamamlanmışsa 'thenReturn' talimatından önce başka bir alaycının davranışını saplıyorsunuz


Bu gerçeğin herhangi bir açıklaması var mı? Çözüm işe yarıyor. Ve "yerinde" sahte yaratımın neden işe yaramadığını anlamıyorum. Alay oluşturduğunuzda ve oluşturulan bir taklidi başka bir alaya referansla ilettiğinizde çalışır.
Capacytron

2
Mükemmel cevap, ÇOK seviyorum! Bunu tek başıma
bulmam yıllar alırdı

4
Harika cevap Luke! Basit kelimelerle çok ayrıntılı açıklama. Teşekkür ederim.
Tomasz Kalkosiński

1
Harika. İşin komik yanı, doğrudan yöntem çağrısı yaptığımda ve yavaşça hata ayıkladığımda işe yarıyor. CGLIB $ BOUND Özniteliği true değerini alacaktır, ancak bir şekilde biraz zaman alır. Direkt yöntem çağrısını kullandığımda ve eğitimden önce durduğumda (... olduğunda), değerin önce yanlış olduğunu ve daha sonra doğru olduğunu görüyorum. Yanlış olduğunda ve eğitim başladığında, bu istisna ortaya çıkar.
Michael Hegner

Günümü gün ettin! Bu, sizi çok fazla zaman kaybettiren türden bir hata! Başlangıçta kotlin ile ilgili bir şey olduğunu düşünmüştüm
Bronx

1
org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
E.g. thenReturn() may be missing.

Geçersiz yöntemlerle alay etmek için aşağıdakileri deneyin:

//Kotlin Syntax

 Mockito.`when`(voidMethodCall())
           .then {
                Unit //Do Nothing
            }
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.