Mockito matchers statik yöntemler ve bu yöntemlere aramalar argümanlar için durmak için aramalar sırasında when
ve 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
, gt
ve startsWith
üzerinde org.mockito.Matchers
ve 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 ( intThat
veya 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
Matchers
olarak ifade edilen intThat
veya argThat
sarmalayan çağrılar . Gibi hamcrest adaptörler ve hala mevcuttur, ancak taşındı yerine.ArgumentMatcher<T>
org.hamcrest.Matcher<T>
argThat
intThat
MockitoHamcrest
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.setPowerLevel
kabul eden bir yöntemdir int
. is(greaterThan(9000))
Bir döndüren Matcher<Integer>
bir şekilde hangi olmaz iş, setPowerLevel
argüman. Mockito eşleştirici intThat
hamcrest tarzı eşleştirici ve iadeler bir o sarar int
o 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ı equals
yö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 any
veya 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 null
için any()
veya argThat(...)
"otomatik Unbox" bir çalışan eğer bir NullPointerException neden olabilir, null
ilkel bir değer.
Eşleştiriciler parametre değerlerini sever eq
ve gt
alı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
, or
venot
. 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 when
veya ç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.
doReturn
ve 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 eq
eş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 . final
Yö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 when
veya 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 NullPointerException
bekliyorsanı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 validateMockitoUsage
sizin tearDown
veya @After
yö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, validateMockitoUsage
kodunuza 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.