как издеваться над частной переменной в классе RestController

#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. Просто на предыдущем шаге было бы уместно.