Mockito: Как частично использовать @ InjectMocks-Annotation для проверки Mock Mvc? - PullRequest
0 голосов
/ 14 февраля 2020

Мне нужно протестировать контроллер, и для большинства деталей все еще достаточно использовать MockMvc. Но есть еще несколько веток, для которых очень сложно создать контрольный пример. Поэтому я использую Mockito для методов-заглушек и исключения для этого специального теста.

Мой контроллер реализует службу, и настройка выглядит следующим образом:

MyController.class :

@RestController
@RequestMapping("/myTest")
public class MyController {

    @Autowired
    private MyService myService;

    @RequestMapping(value = "/", method = { RequestMethod.POST }, produces = "application/json")
    public final int controllerMethod() {
        return myService.serviceMethod();
    }
}

MyService.class :

@Service
public class MyService {
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public int serviceMethod() {
        return 5;
    }
}

Поэтому у меня есть несколько методов тестирования, и в некоторых методах я высмеиваю MyService.class, чтобы бросить исключение для примера. Но в других методах я хочу проверить нормальные функции. Так что здесь возникает проблема. Если тесты не выполняются в правильном порядке, нормальный тест на функциональность не будет работать, потому что, я думаю, MyService.class все еще высмеивается. Таким образом, в этом примере serviceMethod возвращает null вместо 5.

Есть ли способ частично InjectMocks - так я имею в виду только для специальных методов, а не для класса?

Вот пример код:

MyControllerTest.class :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
@WebAppConfiguration
public class MyControllerTest {
    @Autowired
    private WebApplicationContext webApplicationContext;

    @Autowired
    MyService myService;

    @InjectMocks
    @Resource
    MyController myController;

    @Resource
    private FilterChainProxy springSecurityFilterChain;

    private MockMvc mockMvc;

    @Before
    public void setup() throws SQLException {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(springSecurity()).build();
    }

    @Test
    @WithMockUser(username = "validUser", roles = { "ADMIN" })
    public void testMyController() throws Exception {
        mockMvc.perform(post("/myTest/").with(csrf())).andDo(print()).andExpect(status().is2xxSuccessful()).andExpect(jsonPath("$", is(5)));
    }

    @Test
    @WithMockUser(username = "validUser", roles = { "ADMIN" })
    public void testMyControllerException() throws Exception {
        myService = Mockito.spy(MyService.class);

        MockitoAnnotations.initMocks(this);

        Mockito.doThrow(new IndexOutOfBoundsException()).when(myService).serviceMethod();

        mockMvc.perform(post("/myTest/").with(csrf())).andDo(print()).andExpect(status().is4xxClientError());

        Mockito.verify(myService, Mockito.times(1)).serviceMethod();
    }
}

Так что, если я запускаю только один из этих тестов, оба работают хорошо. Но если я запускаю оба вместе, и testMyControllerException() будет выполняться первым, testMyController() завершится неудачно из-за поддельного экземпляра myService-Instance, я думаю.

Есть ли способ исправить эту проблему, или он должен Я разделил эти тесты на два разных тестовых класса?

Я пытался найти способ снять myController.class с аннотации @After с помощью Mockito.reset(myController);. Но у меня не сработало.

Ответы [ 2 ]

0 голосов
/ 24 февраля 2020

Чтобы быть независимым от порядка выполнения и без строгого соблюдения порядка, лучше всего использовать аннотацию класса @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD). Для каждого теста генерируется новыйApplicationContext.

0 голосов
/ 14 февраля 2020

Для jUnit4 вы можете использовать @FixMethodOrder(MethodSorters.NAME_ASCENDING) https://github.com/junit-team/junit4/wiki/Test-execution-order

Я бы лично предпочел иметь его в разных классах.

...