Mockitos ArgumentCaptore kullanarak belirli türde bir liste yakalamanın bir yolu var mı? Bu işe yaramaz:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
Mockitos ArgumentCaptore kullanarak belirli türde bir liste yakalamanın bir yolu var mı? Bu işe yaramaz:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
Yanıtlar:
@Captor ek açıklamasıyla iç içe geçmiş jenerik sorunlardan kaçınılabilir :
public class Test{
@Mock
private Service service;
@Captor
private ArgumentCaptor<ArrayList<SomeType>> captor;
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldDoStuffWithListValues() {
//...
verify(service).doStuff(captor.capture()));
}
}
MockitoAnnotations.initMocks(this)
içinde @Before
yöntemle yerine bir koşucu kullanarak bu dışlayan başka koşucu kullanma yeteneği. Ancak +1, ek açıklamayı işaret ettiğiniz için teşekkür ederiz.
Evet, bu genel bir jenerik problemdir, mockito'ya özgü değildir.
Sınıf nesnesi yoktur ArrayList<SomeType>
ve bu nedenle böyle bir nesneyi a gerektiren bir yönteme güvenli bir şekilde yazamazsınız Class<ArrayList<SomeType>>
.
Nesneyi doğru türe atabilirsiniz:
Class<ArrayList<SomeType>> listClass =
(Class<ArrayList<SomeType>>)(Class)ArrayList.class;
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(listClass);
Bu, güvenli olmayan dökümler hakkında bazı uyarılar verir ve elbette ArgumentCaptor'ınız arasında gerçekten ayrım yapamaz ArrayList<SomeType>
ArrayList<AnotherType>
öğeleri incelemeksizin ve teftiş .
(Diğer cevapta belirtildiği gibi, bu genel bir jenerik problem olsa da, @Captor
ek açıklama ile tip güvenliği sorunu için Mockito'ya özgü bir çözüm vardır .ArrayList<SomeType>
ve ArrayList<OtherType>
.)
Ayrıca tenshi'nin yorumuna bir göz atın . Orijinal kodu Paŭlo Ebermann'dan buna değiştirebilirsiniz (çok daha basit)
final ArgumentCaptor<List<SomeType>> listCaptor
= ArgumentCaptor.forClass((Class) List.class);
ArgumentCaptor<List<SimeType>> argument = ArgumentCaptor.forClass((Class) List.class);
@SuppressWarnings("unchecked")
bağımsız değişken yakalama tanımı satırının üst kısmındaki ek açıklamayı kullanın . Ayrıca, döküm yapmak Class
gereksizdir.
Class
Testlerimdeki döküm gereksiz değil.
Eski java tarzı (tür güvenli olmayan genel) anlambilimden korkmuyorsanız, bu da işe yarar ve oldukça basittir:
ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
verify(subject.method(argument.capture()); // run your code
List<SomeType> list = argument.getValue(); // first captured List, etc.
List<String> mockedList = mock(List.class);
List<String> l = new ArrayList();
l.add("someElement");
mockedList.addAll(l);
ArgumentCaptor<List> argumentCaptor = ArgumentCaptor.forClass(List.class);
verify(mockedList).addAll(argumentCaptor.capture());
List<String> capturedArgument = argumentCaptor.<List<String>>getValue();
assertThat(capturedArgument, hasItem("someElement"));
@ Tenshi'nin ve @ pkalinow'un yorumlarına dayanarak (ayrıca @rogerdpack için kudos), "denetlenmeyen veya güvenli olmayan işlemleri kullanır" uyarısını da devre dışı bırakan bir liste bağımsız değişkeni oluşturmak için basit bir çözümdür :
@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
ArgumentCaptor.forClass(List.class);
Tam örnek burada ve karşılık gelen geçen CI inşa ve burada test çalıştırın .
Ekibimiz bunu bir süredir birim testlerimizde kullanıyor ve bu bizim için en basit çözüm gibi görünüyor.
Junit'in önceki bir sürümü için şunları yapabilirsiniz:
Class<Map<String, String>> mapClass = (Class) Map.class;
ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(mapClass);
Android uygulamamdaki etkinliği test etmekle aynı sorunu yaşadım. Kullandım ActivityInstrumentationTestCase2
ve MockitoAnnotations.initMocks(this);
çalışmadım. Bu sorunu sırasıyla alanı olan başka bir sınıfla çözdüm. Örneğin:
class CaptorHolder {
@Captor
ArgumentCaptor<Callback<AuthResponse>> captor;
public CaptorHolder() {
MockitoAnnotations.initMocks(this);
}
}
Ardından, aktivite testi yönteminde:
HubstaffService hubstaffService = mock(HubstaffService.class);
fragment.setHubstaffService(hubstaffService);
CaptorHolder captorHolder = new CaptorHolder();
ArgumentCaptor<Callback<AuthResponse>> captor = captorHolder.captor;
onView(withId(R.id.signInBtn))
.perform(click());
verify(hubstaffService).authorize(anyString(), anyString(), captor.capture());
Callback<AuthResponse> callback = captor.getValue();
Mockito'nun GitHub'ında bu sorunla ilgili açık bir sorun var.
Sizi testlerinizde ek açıklamalar kullanmaya zorlamayan basit bir geçici çözüm buldum:
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.MockitoAnnotations;
public final class MockitoCaptorExtensions {
public static <T> ArgumentCaptor<T> captorFor(final CaptorTypeReference<T> argumentTypeReference) {
return new CaptorContainer<T>().captor;
}
public static <T> ArgumentCaptor<T> captorFor(final Class<T> argumentClass) {
return ArgumentCaptor.forClass(argumentClass);
}
public interface CaptorTypeReference<T> {
static <T> CaptorTypeReference<T> genericType() {
return new CaptorTypeReference<T>() {
};
}
default T nullOfGenericType() {
return null;
}
}
private static final class CaptorContainer<T> {
@Captor
private ArgumentCaptor<T> captor;
private CaptorContainer() {
MockitoAnnotations.initMocks(this);
}
}
}
Burada olan , @Captor
ek açıklama ile yeni bir sınıf oluşturmak ve onu esir enjekte etmek. Sonra biz sadece esir ayıklamak ve statik yöntemimizi iade.
Testinizde şu şekilde kullanabilirsiniz:
ArgumentCaptor<Supplier<Set<List<Object>>>> fancyCaptor = captorFor(genericType());
Veya Jackson'a benzeyen sözdizimi ile TypeReference
:
ArgumentCaptor<Supplier<Set<List<Object>>>> fancyCaptor = captorFor(
new CaptorTypeReference<Supplier<Set<List<Object>>>>() {
}
);
Çalışır, çünkü Mockito aslında herhangi bir tür bilgiye ihtiyaç duymaz (örneğin serileştiricilerin aksine).
ArrayList
). Her zamanList
arayüzü kullanabilirsiniz ve gerçeği temsil etmek istiyorsanız, bu kovaryant, o zaman kullanabilirsinizextends
:ArgumentCaptor<? extends List<SomeType>>