2015-11-04 22 views
7

Mi piacerebbe testare un controller di riposo Spring Boot, che è protetto usando Spring security, e utilizzare mazze al suo interno. Ho provato con Mockito, ma penso che qualsiasi strumento di derisione dovrebbe fare il trucco.Spring MockMVC, Spring security e Mockito

per abilitare la protezione della molla nel mio test, prima ho fatto come segue:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = Main.class) 
@TestPropertySource(value="classpath:application-test.properties") 
@WebAppConfiguration 
@ContextConfiguration 
public class MyTest{ 

    protected MockMvc mockMvc; 

    @Autowired 
    private WebApplicationContext wac; 

    @Before 
    public void setUp(){ 
     mockMvc = MockMvcBuilders 
       .webAppContextSetup(wac) 
       .apply(SecurityMockMvcConfigurers.springSecurity()) 
       .build(); 
    } 

    @Test 
    public void doTheTest(){ 
     mockMvc.perform(post("/user/register") 
      .with(SecurityMockMvcRequestPostProcessors.csrf()) 
      .content(someContent())); 
    } 
} 

Fino a quando non, funziona bene.

Dopo questo passaggio, ho voluto aggiungere dei mock per testare il mio controller protetto in isolamento.

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = Main.class) 
@TestPropertySource(value="classpath:application-test.properties") 
@WebAppConfiguration 
@ContextConfiguration 
public class MyTest{ 

    protected MockMvc mockMvc; 

    @Mock 
    private Myservice serviceInjectedInController; 

    @InjectMocks 
    private MyController myController; 

    @Autowired 
    private WebApplicationContext wac; 

    @Before 
    public void setUp(){ 
     mockMvc = MockMvcBuilders 
       .webAppContextSetup(wac) 
       .apply(SecurityMockMvcConfigurers.springSecurity()) 
       .build(); 
    } 

    @Test 
    public void doTheTest(){ 
     mockMvc.perform(post("/user/register") 
      .with(SecurityMockMvcRequestPostProcessors.csrf()) 
      .content(someContent())); 
    } 
} 

Purtroppo, il servizio deriso non viene iniettato nel controllore, in quanto non v'è nulla in relazione il MockMVC e Mocks, quindi i mock non vengono iniettati nel controllore.

Così ho provato a cambiare la configurazione del MockMVC, come segue:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = Main.class) 
@TestPropertySource(value="classpath:application-test.properties") 
@WebAppConfiguration 
@ContextConfiguration 
public class MyTest{ 

    protected MockMvc mockMvc; 

    @Mock 
    private Myservice serviceInjectedInController; 

    @InjectMocks 
    private MyController myController; 


    @Before 
    public void setUp(){ 
     mockMvc = MockMvcBuilders 
       .standAloneSetup(myController) 
       .apply(SecurityMockMvcConfigurers.springSecurity()) 
       .build(); 
    } 

    @Test 
    public void doTheTest(){ 
     mockMvc.perform(post("/user/register") 
      .with(SecurityMockMvcRequestPostProcessors.csrf()) 
      .content(someContent())); 
    } 
} 

Ma in questo caso, ho un altro problema. sicurezza primavera si lamenta la configurazione:

java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used. 

ho altra idea per rendere la sicurezza e beffardo. Qualche idea? O dovrei fare un altro modo?

Grazie.

+0

stai usando Primavera di sicurezza 4+ versione? – Ritesh

+0

Sto usando Spring-boot 1.2.7.RELEASE e ho sostituito la sicurezza Spring predefinita per usare 4.0.2 –

+0

@Remi Hai mai risolto questo? – hvgotcodes

risposta

9

Per impostazione predefinita, l'integrazione cerca un bean con il nome di "springSecurityFilterChain". Nell'esempio che è stato fornito, viene utilizzata una configurazione autonoma che significa che MockMvc non sarà a conoscenza dello WebApplicationContext fornito all'interno del test e quindi non sarà in grado di cercare il bean "springSecurityFilterChain".

Il modo più semplice per risolvere questo è quello di utilizzare qualcosa di simile:

MockMvc mockMvc = MockMvcBuilders 
      // replace standaloneSetup with line below 
      .webAppContextSetup(wac) 
      .alwaysDo(print()) 
      .apply(SecurityMockMvcConfigurers.springSecurity()) 
      .build(); 

Se davvero si vuole utilizzare uno standaloneSetup (in realtà non ha senso dal momento che si dispone già di un WebApplicationContext), è in grado di fornire in modo esplicito lo springSecurityFilterChain utilizzando:

@Autowired 
FilterChainProxy springSecurityFilterChain; 

@Before 
public void startMocks(){ 
    controller = wac.getBean(RecipesController.class); 

    MockMvc mockMvc = MockMvcBuilders 
      .standaloneSetup(controller) 
      .alwaysDo(print()) 
      .apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain)) 
      .build(); 

    MockitoAnnotations.initMocks(this); 
} 
+0

Dimmi se ho torto, ma usare 'standaloneSetup' è l'unico modo per avere un controllo sufficiente sul controller per essere in grado di iniettare Mock all'interno. oppure c'è un'altro modo? –

+0

È possibile creare una configurazione di prova che fornisca mock per i propri servizi. Quindi escludere la configurazione con i servizi effettivi. In alternativa, è possibile utilizzare entrambe le configurazioni e contrassegnare '@ Primario' nella versione fittizia dei servizi. Per impostare le aspettative e verificare puoi '@ Autowire' i servizi di simulazione in. –