Mockito'nun sınıfları genel parametrelerle alay etmek için kullanma


280

Genel parametrelerle bir sınıfı alay etmenin temiz bir yöntemi var mı? Diyelim ki bir sınıf Foo<T>için a Foo<Bar>. Aşağıdakileri yeterince kolayca yapabilirim:

Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

Varsayım getValue(), genel türü döndürür T. Ama bunu daha sonra beklediğim bir yönteme geçirdiğimde yavru kedi olacak Foo<Bar>. Döküm bunu yapmanın tek yolu mu?

Yanıtlar:


280

Bence onu yayınlamanız gerekiyor, ama çok kötü olmamalı:

Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue()).thenReturn(new Bar());

34
Evet ama hala bir uyarınız var. Uyarıdan kaçınmak mümkün mü?
— odwl

12
@SuppressWarnings ("işaretlenmemiş")
— qualidafial

18
Bir birim testindeki sahte bir nesneden bahsettiğimiz için bunun tamamen kabul edilebilir olduğunu düşünüyorum.
— Magnilex

1
@demaniak Hiç çalışmıyor. Bağımsız değişken eşleştiricileri bu bağlamda kullanılamaz.
— Krzysztof Krasoń

1
@demaniak Bu iyi derlenecek, ancak testi çalıştırırken InvalidUseOfMatchersException (bir RuntimeException olan)
— atacak

277

Bunun bir başka yolu @Mockbunun yerine ek açıklama kullanmaktır. Her durumda çalışmaz, ancak çok daha seksi görünüyor :)

İşte bir örnek:

@RunWith(MockitoJUnitRunner.class)
public class FooTests {

    @Mock
    public Foo<Bar> fooMock;

    @Test
    public void testFoo() {
        when(fooMock.getValue()).thenReturn(new Bar());
    }
}

MockitoJUnitRunnerİle açıklamalı alanları başlatır @Mock.


3
bu 1.9.5'te kullanımdan kaldırılmıştır. :( Benim için çok daha temiz görünüyor.
— Kod Novitiate,

12
@CodeNovitiate 1.9.5'te MockitoJUnitRunner ve Mock'ta herhangi bir kullanımdan kaldırma notu bulamadım. Peki, kullanımdan kaldırılan nedir? (Evet, org.mockito.MockitoAnnotations.Mock kullanımdan kaldırıldı, ancak bunun yerine org.mockito.Mock kullanmalısınız)
— neu242

12
Aferin, bu benim için mükemmel çalıştı. Sadece "daha seksi" değil, kullanmadan uyarıdan kaçınır SuppressWarnings. Bir nedenden dolayı uyarılar var, onları baskılama alışkanlığı içinde olmamak daha iyi. Teşekkürler!
— Nicole

4
@MockBunun yerine kullanmaktan hoşlanmadığım bir şey var mock(): inşaat süresi boyunca alanlar hala boş, bu yüzden o anda bağımlılıklar ekleyemiyorum ve alanları sonlandıramıyorum. Birincisi @Beforeelbette açıklamalı bir yöntemle çözülebilir .
— Rüdiger Schulz

3
Başlamak için sadece MockitoAnnotations.initMocks (this) 'u arayın;
— borjab

42

Her zaman belirtmek istediğiniz genel türü karşılayacak bir ara sınıf / arabirim oluşturabilirsiniz. Örneğin, Foo bir arayüzse, test sınıfınızda aşağıdaki arayüzü oluşturabilirsiniz.

private interface FooBar extends Foo<Bar>
{
}

Foo'nun nihai olmayan bir sınıf olduğu durumlarda , sınıfı aşağıdaki kodla genişletebilir ve aynı şeyi yapabilirsiniz:

public class FooBar extends Foo<Bar>
{
}

Sonra yukarıdaki örneklerden herhangi birini aşağıdaki kodla tüketebilirsiniz:

Foo<Bar> mockFoo = mock(FooBar.class);
when(mockFoo.getValue()).thenReturn(new Bar());

4
FooBir arayüz veya nihai olmayan bir sınıf sağlandığında , bu oldukça zarif bir çözüm gibi görünüyor. Teşekkürler.
— Tim Clemons

Cevabı, final olmayan sınıflara da örnek olacak şekilde güncelledim. İdeal olarak bir arayüze kodlama yaparsınız, ancak durum her zaman böyle olmayacaktır. İyi yakalama!
— dsingleton

16

Bir test yardımcı programı yöntemi oluşturun . Birden fazla kez ihtiyacınız varsa özellikle yararlıdır.

@Test
public void testMyTest() {
    // ...
    Foo<Bar> mockFooBar = mockFoo();
    when(mockFooBar.getValue).thenReturn(new Bar());

    Foo<Baz> mockFooBaz = mockFoo();
    when(mockFooBaz.getValue).thenReturn(new Baz());

    Foo<Qux> mockFooQux = mockFoo();
    when(mockFooQux.getValue).thenReturn(new Qux());
    // ...
}

@SuppressWarnings("unchecked") // still needed :( but just once :)
private <T> Foo<T> mockFoo() {
    return mock(Foo.class);
}

Alay etmek istediğiniz sınıfta geçen genel bir yardımcı program yapmak için cevabınızı uzatabiliriz.
— William Dutton

1
@WilliamDutton static <T> T genericMock(Class<? super T> classToMock) { return (T)mock(classToMock); }bile tek bir bastırmaya ihtiyaç duymaz :) Ama dikkatli ol, Integer num = genericMock(Number.class)derler, ama atar ClassCastException. Bu sadece en yaygın G<P> mock = mock(G.class)durum için faydalıdır .
— TWiStErRob

6

Birinin, yanlışlıkla bastırılan diğer uyarıları göz ardı edebileceği için sınıflardaki veya yöntemlerdeki uyarıları bastırmaması gerektiğine katılıyorum. Ancak IMHO, yalnızca tek bir kod satırını etkileyen bir uyarıyı bastırmak kesinlikle mantıklıdır.

@SuppressWarnings("unchecked")
Foo<Bar> mockFoo = mock(Foo.class);

3

İşte ilginç bir durum: yöntem genel koleksiyonu alır ve aynı temel türün genel koleksiyonunu döndürür. Örneğin:

Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);

Bu yöntem Mockito anyCollectionOf eşleştiricisi ve Cevap kombinasyonu ile alay edilebilir.

when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
     new Answer<Collection<Assertion>>() {
         @Override
         public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
             return new ArrayList<Assertion>();
         }
     });
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.