Je souhaite tester un composant Spring et ce composant possède un attribut autowired que je dois modifier aux fins des tests unitaires. Le problème est que la classe utilise le composant autowired dans la méthode post-construction, je ne suis donc pas en mesure de le remplacer (c'est-à-dire via ReflectionTestUtils) avant son utilisation réelle.
Comment devrais-je faire ça?
C'est la classe que je veux tester:
@Component
public final class TestedClass{
@Autowired
private Resource resource;
@PostConstruct
private void init(){
//I need this to return different result
resource.getSomething();
}
}
Et voici la base d'un cas de test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= "classpath:applicationContext.xml")
public class TestedClassTest{
@Autowired
private TestedClass instance;
@Before
private void setUp(){
//this doesn't work because it's executed after the bean is instantiated
ReflectionTestUtils.setField(instance, "resource", new Resource("something"));
}
}
Existe-t-il un moyen de remplacer la ressource par autre chose avant que la méthode postconstruct soit appelée? Vous voulez dire au coureur Spring JUnit d'autowire une instance différente?
Vous pouvez fournir un nouveau fichier testContext.xml dans lequel le fichier @Autowired
Le bean que vous définissez est du type dont vous avez besoin pour votre test.
Vous pouvez utiliser Mockito . Je ne suis pas sûr avec PostConstruct
en particulier, mais cela fonctionne généralement:
// Create a mock of Resource to change its behaviour for testing
@Mock
private Resource resource;
// Testing instance, mocked `resource` should be injected here
@InjectMocks
@Resource
private TestedClass testedClass;
@Before
public void setUp() throws Exception {
// Initialize mocks created above
MockitoAnnotations.initMocks(this);
// Change behaviour of `resource`
when(resource.getSomething()).thenReturn("Foo");
}
Spring Boot 1.4 a introduit une annotation de test appelée @MockBean
. Alors maintenant, se moquer et espionner les haricots du printemps est supporté nativement par Spring Boot.
J'ai créé blog sur le sujet . Il contient également un lien vers le référentiel Github avec un exemple de travail.
L'astuce consiste à utiliser la configuration de test, où vous remplacez le haricot printanier d'origine par un faux. Vous pouvez utiliser @Primary
et @Profile
annotations pour cette astuce.
Vous pouvez remplacer les définitions de haricots avec des mocks avec spring-reinject https://github.com/sgri/spring-reinject/
Une autre approche des tests d’intégration consiste à définir une nouvelle classe de configuration et à la définir comme votre @ContextConfiguration
. Dans la configuration, vous pourrez vous moquer de vos beans et vous devez également définir tous les types de beans que vous utilisez dans le flux test/s. Pour donner un exemple:
@RunWith(SpringRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class MockTest{
@Configuration
static class ContextConfiguration{
// ... you beans here used in test flow
@Bean
public MockMvc mockMvc() {
return MockMvcBuilders.standaloneSetup(/*you can declare your controller beans defines on top*/)
.addFilters(/*optionally filters*/).build();
}
//Defined a mocked bean
@Bean
public MyService myMockedService() {
return Mockito.mock(MyService.class);
}
}
@Autowired
private MockMvc mockMvc;
@Autowired
MyService myMockedService;
@Before
public void setup(){
//mock your methods from MyService bean
when(myMockedService.myMethod(/*params*/)).thenReturn(/*my answer*/);
}
@Test
public void test(){
//test your controller which trigger the method from MyService
MvcResult result = mockMvc.perform(get(CONTROLLER_URL)).andReturn();
// do your asserts to verify
}
}