2016-05-22 9 views
2

Ich habe Schwierigkeiten, Mockito und MockMvc zusammenzuarbeiten, wenn ich das webAppContextSetup zusammen benutze. Ich bin neugierig, ob es daran liegt, dass ich die beiden auf eine Weise mische, die sie nie beabsichtigt haben.Soll Mockito mit MockMvcs webAppContextSetup in Spring 4 verwendet werden?

Quelle: https://github.com/zgardner/spring-boot-intro/blob/master/src/test/java/com/zgardner/springBootIntro/controller/PersonControllerTest.java

Hier ist der Test, den ich laufen werde:

package com.zgardner.springBootIntro.controller; 

import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.InjectMocks; 
import org.mockito.Mock; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.support.DefaultListableBeanFactory; 
import org.springframework.boot.test.SpringApplicationConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
import org.springframework.test.context.web.WebAppConfiguration; 
import org.springframework.test.web.servlet.MockMvc; 
import org.springframework.test.web.servlet.setup.MockMvcBuilders; 
import org.springframework.web.context.WebApplicationContext; 

import static java.lang.Math.toIntExact; 
import static org.hamcrest.Matchers.is; 
import static org.mockito.MockitoAnnotations.initMocks; 
import static org.mockito.Mockito.when; 
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; 

import com.zgardner.springBootIntro.Application; 
import com.zgardner.springBootIntro.service.PersonService; 
import com.zgardner.springBootIntro.model.PersonModel; 

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = Application.class) 
@WebAppConfiguration 
public class PersonControllerTest { 

    private MockMvc mockMvc; 

    @Autowired 
    private WebApplicationContext webApplicationContext; 

    @Autowired 
    private DefaultListableBeanFactory beanFactory; 

    @Mock 
    private PersonService personService; 

    @InjectMocks 
    private PersonController personController; 

    @Before 
    public void setup() { 
     initMocks(this); 

     // beanFactory.destroySingleton("personController"); 
     // beanFactory.registerSingleton("personController", personController); 

     mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 
    } 

    @Test 
    public void getPersonById() throws Exception { 
     Long id = 999L; 
     String name = "Person name"; 

     when(personService.findById(id)).thenReturn(new PersonModel(id, name)); 

     mockMvc.perform(get("/person/getPersonById/" + id)) 
      .andDo(print()) 
      .andExpect(jsonPath("$.id", is(toIntExact(id)))) 
      .andExpect(jsonPath("$.name", is(name))); 
    } 
} 

Ich hatte erwartet, dass, wenn mockMvc die mock dieser HTTP-Aufruf ausgeführt, würde es die PersonController verwende ich in meinem definiert Prüfung. Aber wenn ich durch Debugging, es verwendet den PersonController, die von der SpringJunit4ClassRunner beim Teststart erstellt wurde.

fand ich zwei Möglichkeiten, dies zu Arbeit zu bekommen:

  1. die BeanFactory injizieren, die alte personController Singleton entfernen, und meine eigenen hinzufügen. Das ist hässlich und ich bin kein Fan.
  2. Verbinden Sie alles mit dem StandaloneSetup anstelle von webAppContextSetup. Ich kann dies stattdessen tun, da ich die Bohnenfabrik nicht anfassen muss.

Hier sind einige andere Artikel, die ich gefunden habe, die etwas über das Thema berühren:

Gedanken?

Antwort

0

Ich benutze manchmal Mockito, um Frühlingsbohnen mit der Verwendung von @Primary und @Profile Annotationen zu fälschen. I wrote a blog post about this technique. Es enthält auch einen Link zum vollständig funktionierenden Beispiel, das auf GitHub gehostet wird.

4

Sie könnten Interesse an der new testing features in Spring Boot 1.4 kommen (speziell die neue @MockBean Annotation). Diese sample zeigt, wie ein Dienst verspottet und mit einem Controller-Test verwendet werden kann.

2

Aus irgendeinem Grund werden die Mockito-Anmerkungen @Mock und @InjectMocks in diesem Fall nicht funktionieren.

Hier ist, wie ich es geschafft, damit es funktioniert:

  • Instantiate die personService bean manuell Ihre eigenen Test-Kontext mit
  • machen Mockito für dieses personService ein Modell erstellen.
  • lassen Sie Spring diese Mocks in den Controller PersonController injizieren.

Sie sollten Ihre TestConfig haben:

@Configuration 
public class ControllerTestConfig { 

    @Bean 
    PersonService personService() { 
    return mock(PersonService.class); 
    } 

} 

In Ihrem PersonControllerTest, werden Sie nicht die personController mehr brauchen, denn es ist durch die mockMvc durch die perform Methode verwaltet. Sie müssen auch initMocks() nicht ausführen, weil Sie Ihre Mocks manuell in der Spring-Konfiguration initialisieren. Sie sollten folgendes haben:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = {Application.class, ControllerTestConfig.class}) 
@WebAppConfiguration 
public class PersonControllerTest { 

    private MockMvc mockMvc; 

    @Autowired 
    private WebApplicationContext webApplicationContext; 

    @Autowired 
    PersonService personService; 

    @Before 
    public void setup() { 
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 
    } 

    @Test 
    public void getPersonById() throws Exception { 
    Long id = 999L; 
    String name = "Person name"; 

    when(personService.findById(id)).thenReturn(new PersonModel(id, name)); 

    mockMvc.perform(get("/person/getPersonById/" + id)) 
     .andDo(print()) 
     .andExpect(jsonPath("$.id", is(toIntExact(id)))) 
     .andExpect(jsonPath("$.name", is(name))); 
    } 
} 
Verwandte Themen