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.