Mockito @InjectMocks не работает для полей с одинаковым типом
Я был очень удивлен, узнав, что следующий простой пример кода не работает для всех версий Mockito > 1.8.5
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
@Mock(name = "b2")
private B b2;
@InjectMocks
private A a;
@Test
public void testInjection() throws Exception {
assertNotNull(a.b2); //fails
assertNull(a.b1); //also fails, because unexpectedly b2 mock gets injected here
}
static class A{
private B b1;
private B b2;
}
interface B{}
}
в javadocs (http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html) есть цитата:
Примечание 1: Если у вас есть поля с тем же типом (или тем же стиранием), это лучше назвать все @ Mock аннотированные поля с соответствующими полями, в противном случае Mockito может запутаться и инъекции этого не случится.
означает ли это, что если у меня есть несколько полей с одинаковым типом, я не могу издеваться только над одним из них, а должен определить @Mock
на все поля с одинаковым типом?
Известно ли ограничение и есть ли причина, по которой оно еще не было исправлено?
Это должно быть просто, чтобы соответствовать @Mock
имена полей, не так ли?
2 ответов
похоже, Mockito использует алгоритм, описанный в их JavaDoc
Если я правильно понимаю, он сначала сортирует по типу (в данном случае только 1 B), а затем сортирует по имени (здесь нет изменений). Он, наконец, впрыснет с помощью реализация интерфейса OngoingInjector, который, похоже, ищет первое поле и вводит его.
поскольку у вас есть только 1 B, определенный, и есть 2 поля B в макете, он увидит совпадение первый экземпляр на поле и стоп. Это потому что mocks.size() == 1
на NameBasedCandidateFilter
. Поэтому он остановит фильтровать и впрыснет его сразу. Если вы создадите несколько насмешек одного типа, они будут отсортированы по имени и введены соответственно.
я смог заставить его работать, когда я создал несколько насмешек (но меньше, чем количество полей) определенного типа.
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
@Mock(name = "b2")
private B b2;
@Mock(name = "b3")
private B b3;
@InjectMocks
private A a;
@Test
public void testInjection() {
System.out.println(this.a);
}
static class A {
private B b1;
private B b2;
private B b3;
}
interface B {
}
}
это правильно введет b2 в a.b2 и b3 в a.b3 вместо a.b1 и.В2 (первые 2 поля, определенные в).
вы всегда можете оставить проблему GitHub в своем репозитории с улучшением или изменением алгоритма фильтрации инъекций, чтобы посмотреть.
это задокументировано в mockito как работа вокруг, если существует несколько насмешек одного и того же типа. Он не разрешает реализацию на основе предоставленного имени (ie @Mock(name = "b2")
). Алгоритм, который он использует для разрешения реализации, - это имя поля введенной зависимости. Таким образом, ваш код выше будет правильно разрешен (b2
=>@Mock private B b2
и b3
=>@Mock private B b3
).
другой обходной путь-использовать инъекцию конструктора, которая является рекомендуемым способом инъекции зависимости.