Mockito matchers statik yöntemler ve bu yöntemlere aramalar argümanlar için durmak için aramalar sırasında whenve verify.
Hamcrest eşleştiricileri (arşivlenmiş sürüm) (veya Hamcrest tarzı eşleştiriciler), nesne Eşleştiricinin ölçütleriyle eşleşirse doğru döndüren Matcher<T>bir yöntemi uygulayan ve ortaya çıkaran durumsuz, genel amaçlı nesne örnekleridir matches(T). Yan etkilerden arındırılmış olmaları amaçlanmıştır ve genellikle aşağıdaki gibi iddialarda kullanılırlar.
/* Mockito */ verify(foo).setPowerLevel(gt(9000));
/* Hamcrest */ assertThat(foo.getPowerLevel(), is(greaterThan(9000)));
Mockito eşleştiriciler, Hamcrest tarzı eşleştiricilerden ayrı olarak mevcuttur, böylece eşleşen ifadelerin açıklamaları doğrudan yöntem çağrılarına sığar : Mockito eşleştiricileri T, Hamcrest eşleme yöntemlerinin Eşleştirici nesnelerini (türden Matcher<T>) döndürdüğü yerde geri döner .
Mockito matchers gibi statik yöntemlerle çağrılır eq, any, gtve startsWithüzerinde org.mockito.Matchersve org.mockito.AdditionalMatchers. Mockito sürümlerinde değişen adaptörler de vardır:
- Mockito 1.x için,
Matchersöne çıkan bazı aramalar ( intThatveya gibi argThat), Hamcrest eşleştiricilerini doğrudan parametre olarak kabul eden Mockito eşleştiricileridir. ArgumentMatcher<T>uzatılmış org.hamcrest.Matcher<T>iç hamcrest temsil kullanılır ve bir oldu olan hamcrest eşleştirici temel sınıf yerine mockito Eşleştirici herhangi bir tür.
- Mockito 2.0+ için Mockito artık Hamcrest'e doğrudan bağımlı değil. artık uygulanmayan ancak benzer şekillerde kullanılan nesneler
Matchersolarak ifade edilen intThatveya argThatsarmalayan çağrılar . Gibi hamcrest adaptörler ve hala mevcuttur, ancak taşındı yerine.ArgumentMatcher<T>org.hamcrest.Matcher<T>argThatintThatMockitoHamcrest
Eşleştiricilerin Hamcrest veya sadece Hamcrest tarzı olmasına bakılmaksızın, şu şekilde uyarlanabilirler:
/* Mockito matcher intThat adapting Hamcrest-style matcher is(greaterThan(...)) */
verify(foo).setPowerLevel(intThat(is(greaterThan(9000))));
Yukarıdaki ifadede: foo.setPowerLevelkabul eden bir yöntemdir int. is(greaterThan(9000))Bir döndüren Matcher<Integer>bir şekilde hangi olmaz iş, setPowerLevelargüman. Mockito eşleştirici intThathamcrest tarzı eşleştirici ve iadeler bir o sarar into kadar olabilir bağımsız değişken olarak görünür; Mockito eşleştiricileri gt(9000), örnek kodun ilk satırında olduğu gibi , tüm ifadeyi tek bir çağrıya sarar.
Eşleştiriciler ne yapar / ne yapar?
when(foo.quux(3, 5)).thenReturn(true);
Argüman eşleştiriciler kullanılmadığında, Mockito argüman değerlerinizi kaydeder ve bunları equalsyöntemleriyle karşılaştırır .
when(foo.quux(eq(3), eq(5))).thenReturn(true); // same as above
when(foo.quux(anyInt(), gt(5))).thenReturn(true); // this one's different
Bir eşleştiriciyi anyveya gt(daha büyük) olarak çağırdığınızda, Mockito, Mockito'nun bu eşitlik kontrolünü atlamasına ve seçtiğiniz eşleşmeyi uygulamasına neden olan bir eşleştirme nesnesi depolar. Bu durumda, argumentCaptor.capture()daha sonraki inceleme için argümanını kaydeden bir eşleştirici depolar.
Eşleyiciler geri kukla değerleri , örneğin, sıfır, boş koleksiyonları ya da null. Mockito, 0 için anyInt()veya any(Integer.class)boş bir List<String>için gibi güvenli, uygun bir kukla değer döndürmeye çalışır anyListOf(String.class). Tip silme yüzünden olsa da, mockito herhangi bir değer ama geri dönmek için tür bilgileri yoksun nulliçin any()veya argThat(...)"otomatik Unbox" bir çalışan eğer bir NullPointerException neden olabilir, nullilkel bir değer.
Eşleştiriciler parametre değerlerini sever eqve gtalır; ideal olarak, bu değerler stubbing / doğrulama başlamadan önce hesaplanmalıdır. Başka bir aramayla alay ederken bir sahte arama yapmak, saplama işlemini engelleyebilir.
Eşleştirme yöntemleri dönüş değerleri olarak kullanılamaz; ifadesine yolu yoktur thenReturn(anyInt())veya thenReturn(any(Foo.class))Mockito örneğin,. Mockito'nun, stubbing çağrılarında hangi örneğin döneceğini tam olarak bilmesi gerekir ve sizin için keyfi bir dönüş değeri seçmez.
Uygulama ayrıntıları
Eşleştiriciler, ArgumentMatcherStorage adlı bir sınıfta bulunan bir yığın içinde saklanır (Hamcrest tarzı nesne eşleştiriciler olarak) . MockitoCore ve Matchers'ın her biri , statik olarak bir ThreadLocal tutan MockingProgress örneklerini içeren bir ThreadSafeMockingProgress örneğine sahiptir . Somut bir ArgumentMatcherStorageImpl içeren bu MockingProgressImpl'dir . Sonuç olarak, sahte ve eşleştirici durumu statiktir, ancak Mockito ve Matchers sınıfları arasında tutarlı bir şekilde iş parçacığı kapsamına sahiptir.
Çoğu eşleştirici aramalar sadece gibi matchers için bir istisna ile, bu yığınına eklemek and, orvenot . Bu , bir yöntemi çağırmadan önce soldan sağa argümanları değerlendiren Java'nın değerlendirme sırasına mükemmel bir şekilde karşılık gelir (ve buna dayanır) :
when(foo.quux(anyInt(), and(gt(10), lt(20)))).thenReturn(true);
[6] [5] [1] [4] [2] [3]
Bu irade:
anyInt()Yığına ekleyin .
gt(10)Yığına ekleyin .
lt(20)Yığına ekleyin .
- Kaldır
gt(10)ve lt(20)ekle and(gt(10), lt(20)).
- Çağrı
foo.quux(0, 0), (aksi belirtilmedikçe) varsayılan değeri döndürür false. Mockito dahili quux(int, int)olarak en son çağrı olarak işaretler .
when(false)Çağrının argümanını atan ve 5'te quux(int, int)tanımlanan saplama yöntemine hazırlayan çağrı , yalnızca iki geçerli durum yığın uzunluğu 0 (eşitlik) veya 2 (eşleştiriciler) ve yığın üzerinde iki eşleştirici vardır (adım 1 ve 4), bu nedenle Mockito, yöntemi any()ilk argümanı ve and(gt(10), lt(20))ikinci argümanı için bir eşleştirici ile saplar ve yığını temizler.
Bu, birkaç kuralı gösterir:
Mockito quux(anyInt(), 0)ve arasındaki farkı söyleyemez quux(0, anyInt()). İkisi de quux(0, 0)yığında bir int eşleştiriciye sahip bir çağrı gibi görünüyor . Sonuç olarak, bir eşleştirici kullanırsanız, tüm bağımsız değişkenleri eşleştirmeniz gerekir.
Çağrı emri sadece önemli değil, tüm bunların yürümesini sağlayan şey . Eşleştiricileri değişkenlere çıkarmak genellikle işe yaramaz, çünkü genellikle arama sırasını değiştirir. Ancak eşleştiricileri yöntemlere çıkarmak harika çalışıyor.
int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */ when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.
Yığın, Mockito'nun onu çok dikkatli bir şekilde denetleyemeyeceği kadar sık değişir. Yığını yalnızca Mockito veya bir taklit ile etkileşime girdiğinizde kontrol edebilir ve hemen kullanıldıklarını veya yanlışlıkla terk edildiklerini bilmeden eşleştiricileri kabul etmesi gerekir. Teorik olarak, yığın, bir whenveya çağrısının dışında her zaman boş olmalıdır verify, ancak Mockito bunu otomatik olarak kontrol edemez. İle manuel olarak kontrol edebilirsiniz Mockito.validateMockitoUsage().
Bir çağrıda when, Mockito aslında söz konusu yöntemi çağırır; bu, yöntemi bir istisna atacak şekilde (veya sıfır olmayan veya boş olmayan değerler gerektirdiğinde) bir istisna atar.
doReturnve doAnswer(vs) yok olup , gerçek bir yöntem çağırmak ve genellikle faydalı bir alternatiftir.
Stubbing'in ortasında bir sahte yöntem çağırmış olsaydınız (örneğin, bir eqeşleştirici için bir cevabı hesaplamak için ), Mockito bunun yerine yığın uzunluğunu bu çağrıya göre kontrol eder ve muhtemelen başarısız olur.
Son bir yöntemi saplamak / doğrulamak gibi kötü bir şey yapmaya çalışırsanız , Mockito gerçek yöntemi çağıracak ve yığında fazladan eşleştiriciler bırakacaktır . finalYöntem çağrısı bir özel durum olmayabilir, ama bir alabilirsiniz InvalidUseOfMatchersException mock ile başıboş matchers sonraki etkileşim dan.
Yaygın sorunlar
InvalidUseOfMatchersException :
Eşleştiriciler kullanıyorsanız, her bağımsız değişkenin tam olarak bir eşleştirici çağrısı olup olmadığını ve bir arama whenveya verifyçağrı dışında eşleştirici kullanmadığınızı kontrol edin . Eşleştiriciler asla stubed dönüş değerleri veya alanlar / değişkenler olarak kullanılmamalıdır.
Bir eşleştirme argümanı sağlamanın bir parçası olarak sahte çağırmadığınızı kontrol edin.
Bir eşleştirici ile son bir yöntemi saplamaya / doğrulamaya çalışmadığınızı kontrol edin. Bu, yığın üzerinde bir eşleştirici bırakmanın harika bir yoludur ve son yönteminiz bir istisna oluşturmadıkça, alay ettiğiniz yöntemin nihai olduğunu anladığınız tek zaman bu olabilir.
İlkel bağımsız değişkenlerle NullPointerException: 0 (Integer) any()döndürürken null any(Integer.class)döndürür; Tamsayı yerine bir NullPointerExceptionbekliyorsanız, bu a neden olabilir int. Her durumda, anyInt()sıfıra dönecek ve ayrıca otomatik kutulama adımını atlayacak olanı tercih edin.
NullPointerException veya diğer istisnalar: Çağrılar when(foo.bar(any())).thenReturn(baz)gerçekte çağırır foo.bar(null) ; bu, boş bir bağımsız değişken alırken bir istisna atmaya başlamış olabilirsiniz. doReturn(baz).when(foo).bar(any()) Öğesine geçmek , stublanmış davranışı atlar .
Genel sorun giderme
MockitoJUnitRunner'ı kullanın veya validateMockitoUsagesizin tearDownveya @Afteryönteminizi açıkça çağırın (koşucunun sizin için otomatik olarak yapacağı). Bu, eşleştiricileri kötüye kullanıp kullanmadığınızı belirlemenize yardımcı olacaktır.
Hata ayıklama amacıyla, validateMockitoUsagekodunuza doğrudan çağrı ekleyin . Bu, yığında herhangi bir şey varsa atacaktır, bu kötü bir semptom için iyi bir uyarıdır.