#java #spring #junit #mockito
#java #весна #junit #мокито #mockito
Вопрос:
Я провожу некоторое веб-модульное тестирование с помощью Spring. есть ли способ, которым я могу издеваться над экземпляром, MyProcessor
который устанавливается в @PostConstruct
? Я пробовал с @MockBean
, но он устанавливается как null и получает исключение нулевого указателя?
Я использую фабрику для создания экземпляра MyProcessor
на основе некоторого логического флага. Но если есть совершенно другой подход, который сделал бы мой тест чище, я открыт для идей.
Пожалуйста, обратите внимание, что я использую Junit 5.
public class Controller {
private final AProcessorFactory factory;
@Value("${tt.f.processor.async}")
private boolean isAsync;
private MyProcessor myProcessor;
public Controller(final AProcessorFactory factory) {
this.factory= factory;
}
@PostConstruct
public void init() {
myProcessor = factory.getInstance(isAsync);
}
}
@WebMvcTest(Controller.class)
public class ControllerTest{
@MockBean
private MyProcessor processor;
@MockBean
private AProcessorFactory factory;
@Autowired
private MockMvc mockMvc;
@Test
public void test() throws Exception {
when(processor.process(any(Request.class), any(String.class)))
.thenReturn(new TestResponse("123", SUCCESS, "", ""));
}
Комментарии:
1. рефакторинг вашего класса для использования внедрения конструктора поможет улучшить тестируемость вашего кода. постконструкция затруднила бы информирование JUnit об этой инъекции.
2. установите этот флаг в конструкторе a swll
3. как бы я тогда смоделировал / установил это в своем тестовом классе. Как флаг асинхронности, так и экземпляр MyProcessor
4. @shinjw — как бы это выглядело с junit5 и внедрением конструктора? можете ли вы привести один пример
Ответ №1:
Похоже, что ваш myProcessor
фактически создан вашим AProcessorFactory
методом PostConstruct init().
Вы захотите предоставить поведение для своего AProcessorFactory
макета.
Во-первых, вы, вероятно, захотите настроить свой myProcessor
в вашем конструкторе, поскольку @PostConstruct
init()
метод не имеет специальной логики загрузки контекста с ним.
public class Controller {
@Value("${tt.f.processor.async}")
private boolean isAsync;
private MyProcessor myProcessor;
public Controller(final AProcessorFactory factory) {
this.myProcessor = factory.getInstance(isAsync);
}
}
Вы можете указать это на @Before
шаге вашего теста.
@MockBean
private AProcessorFactory factory;
@Before
public void setUp() {
when(processor.process(any(Request.class), any(String.class)))
.thenReturn(new TestResponse("123", SUCCESS, "", ""));
when(factory.getInstance(any())).thenReturn(processor)
}
Spring зарегистрирует ваш макет AProcessorFactory, который был загружен с соответствующим поведением.
Комментарии:
1. Как это будет выглядеть с Junit5? @beforeAll будет работать с PostConstruct?
2. Просто на предыдущем шаге было бы уместно.