@InjectMocks inject @MockBean от Constructor и setter не работает должным образом - PullRequest
0 голосов
/ 07 ноября 2019

Я пробовал так много раз с помощью unsing @RunWith(SpringJUnit4ClassRunner.class) Я пытался создать тестовый пример для класса с инжектором getter и Constructor. Когда я использую @MockBean для инъекции в сеттер, @Mock для инженера-конструктора, а также использую @RunWith(SpringJUnit4ClassRunner.class) и MockitoAnnotations.initMocks(this); инъекцию бобов. Если я прокомментирую MockitoAnnotations.initMocks(this); инжектор конструктора не работает. Теперь все bean-компоненты вводятся идеально, но @Mock bean (Contructor injected) bean-компоненты не работают должным образом, когда его вызывают.

@Component
Class A{
}

@Component
Class B {
}

@Component
Class c{
}

@Component
Class D{
@Atowired
A a;

B b;
C c;
@Autowired
public D(B b,C c){
b=b;
c=c;
}
}

Мой тестовый класс

@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@Mock
B mockB
@Mock
C mockC
@InjectMocks
D mockD

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");

}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before 
}
}

Инъекцииработает правильно, проблема относится к поддельным методам bean-компонентов, которые я использую @Mock не работает должным образом, означает mockB.getValue() и mockC.getValue() retun null, но mockA.getValue() возвращаются правильно, когда я запускаю тест.

Ответы [ 3 ]

1 голос
/ 11 ноября 2019

Если вы запускаете тест с SpringJUnit4ClassRunner.class, тогда вам нужно использовать @MockBean вместо @Mock.

Пожалуйста, обратитесь к документации по загрузочной пружине

Кроме того, вам нужно использовать @Autowired вместо @InjectMocks.

@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@MockBean
B mockB
@MockBean
C mockC
@Autowired
D mockD

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");

}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before 
}
}
0 голосов
/ 13 ноября 2019

Обычные методы инициализации bean-компонентов, такие как SpringJUnit4ClassRunner или MockitoAnnotations.initMocks(this);, обрабатывающие только один тип инъекций за раз. Либо конструктор, либо автоматическая проводная инъекция.

@RunWith(SpringJUnit4ClassRunner.class) означает, что открытый класс SpringJUnit4ClassRunner расширяет BlockJUnit4ClassRunner. SpringJUnit4ClassRunner - это пользовательское расширение JUnit. Он инициализирует макет аннотированных bean-компонентов @MockeBean и @bean во время начального запуска теста. Также запускается и инъекция bean-компонента.

MockitoAnnotations.initMocks(this) метод должен вызываться для инициализации аннотированных полей. В приведенном выше примере initMocks () вызывается в методе @Before (JUnit4) базового класса теста. Для JUnit3 initMocks () может перейти к методу setup () базового класса.

Чтобы в приведенном выше вопросе вы использовали SpringJUnit4ClassRunner и MockitoAnnotations.initMocks (this);он создаст две фиктивные ссылки на bean-компоненты, для которых вы всегда используете @Mock. Также в приведенном выше потоке кода.

1. В начале выполнения SpringJUnit4ClassRunner он создаст ссылку на bean-компонент для аннотированных атрибутов @Mock и @MockBean. После того, как он создаст внедренный bean-компонент в это время, происходит только конструкторинъекция

2. Выполните @Before и запустите MockitoAnnotations.initMocks(this);, чтобы создать еще одну фиктивную ссылку для аннотированных атрибутов @Mock и заменить только прямые ссылки. и в этот момент запускается автоматический проводной впрыск.

После запуска MockitoAnnotations.initMocks(this); вы увидите, что бобы allk инициализированы и правильно введены. Но бины, которые вводятся через конструктор, эти бины не являются правильной ссылкой, они ссылаются на старую ссылку на бин, созданную SpringJUnit4ClassRunner.

Если вы хотите получить конструктор и автоматическую проводную инъекцию для одного бина, выдолжен использовать ручной бин, вводимый для конструктора. Вы можете сослаться здесь

Решение:

@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@MockBean
B mockB
@MockBean
C mockC
@Autowired
D mockD

@Before
public void setUp() {
mockD = new D(mockA,mockB);
MockitoAnnotations.initMocks(this);
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");

}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before 
}
}
0 голосов
/ 07 ноября 2019

Когда вы запускаете тест с помощью Spring Runner, вы должны указать, что именно вы хотите загрузить в виде бобов (прочитайте, сообщите Spring, что именно должно быть включено в контекст приложения).

Обычно это можетпокончить с аннотацией * 1003.

Я подозреваю, что, поскольку вы не указываете эту аннотацию, spring не загружает ни один из ваших компонентов (A, B, C в вопросе и т. д.).

Теперь @MockBean в основном позволяет "изменять" контекст приложения для целей тестирования. Это достигается путем предоставления имитации вместо реального bean-компонента, который должен был быть загружен в «обычном» контексте приложения.

В этом случае нет смысла вызывать MockitoAnnotations.initMocks(this); Spring сам внедрит mock-файлыкогда все настроено правильно.

...