Spring JUnit: So simulieren Sie eine automatisch verdrahtete Komponente in einer automatisch verdrahteten Komponente

Lesezeit: 4 Minuten

Benutzer-Avatar
NeplatnyUdaj

Ich habe eine Spring-Komponente, die ich testen möchte, und diese Komponente hat ein automatisch verdrahtetes Attribut, das ich zum Zweck des Komponententests ändern muss. Das Problem ist, dass die Klasse die automatisch verdrahtete Komponente innerhalb der Post-Konstruktionsmethode verwendet, sodass ich sie nicht ersetzen kann (z. B. über ReflectionTestUtils), bevor sie tatsächlich verwendet wird.

Wie soll ich das machen?

Dies ist die Klasse, die ich testen möchte:

@Component
public final class TestedClass{

    @Autowired
    private Resource resource;

    @PostConstruct
    private void init(){
        //I need this to return different result
        resource.getSomething();
    }
}

Und das ist die Basis eines Testfalls:

@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"));
    }
}

Gibt es eine Möglichkeit, die Ressource durch etwas anderes zu ersetzen, bevor die Postconstruct-Methode aufgerufen wird? Möchten Sie Spring JUnit Runner mitteilen, dass er eine andere Instanz automatisch verdrahten soll?

Benutzer-Avatar
Anna Subenko

Du könntest benutzen Mockito. Ich bin mir nicht sicher mit PostConstruct speziell, aber das funktioniert im Allgemeinen:

// 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");   
}

  • Ich habe genau das versucht, aber die PostConstruct wird noch vor dem ausgeführt setUp() Methode.

    – NeplatnyUdaj

    10. Oktober 2013 um 16:54 Uhr

  • @NeplatnyUdaj, eine weitere Chance ist mit @BeforeClass Anstatt von @Before. Nicht sicher wie initMocks funktioniert damit aber.

    – Anna Subenko

    10. Oktober 2013 um 19:58 Uhr

  • Das war auch meine Idee, aber MockitoAnnotations.initMocks(Object o) erfordert eine Instanz der Testklasse.

    – NeplatnyUdaj

    11. Oktober 2013 um 8:07 Uhr

  • Oder mit neuer TestUnit5 einfach verwenden @ExtendWith(MockitoExtension.class) vor deiner Probestunde.

    – Ondřej Stašek

    15. Februar 2021 um 13:25 Uhr

Spring Boot 1.4 führte die Testanmerkung namens ein @MockBean. Das Verspotten und Ausspionieren von Spring Beans wird jetzt von Spring Boot nativ unterstützt.

Sie können eine neue testContext.xml bereitstellen, in der die @Autowired Bean, die Sie definieren, ist von dem Typ, den Sie für Ihren Test benötigen.

  • Vielen Dank. Genau das habe ich gemacht und funktioniert. Ich frage mich nur, ob es eine Möglichkeit gibt, das zu tun, ohne einen neuen Kontext zu schreiben (obwohl ich nur den alten importiert und die benötigte Bean überschrieben habe).

    – NeplatnyUdaj

    10. Oktober 2013 um 15:39 Uhr

  • @NeplatnyUdaj versuchen Sie es mit @Qualifier(“myAlternateBean”), dann sollte es Ihr Problem lösen

    – puri

    10. Oktober 2013 um 15:56 Uhr

  • Das ist ein Missverständnis. Dein Vorschlag funktioniert. Es ist einfach nicht genau das, wonach ich gesucht habe. Ich werde es verwenden, bis ich etwas anderes finde. Vielen Dank

    – NeplatnyUdaj

    10. Oktober 2013 um 16:42 Uhr

  • Wenn Sie Autowiring in Tests verwenden, ist es normal, testspezifische Kontexte zu haben, sodass ich mir keine Sorgen machen würde, nach etwas Besserem zu suchen. Die einzigen anderen Möglichkeiten bestehen darin, init zu überschreiben (was bedeutet, dass es nicht privat sein kann) oder Ihre Beans für den Test manuell zu verbinden.

    – matt helliwell

    12. Oktober 2013 um 20:43 Uhr

  • @ph. So machen Sie es in Spring-Boot, wo es keine .xml-Dateien gibt. Muss ich für den Test eine Konfigurationsdatei erstellen?

    – Tarun Maganti

    15. März 2017 um 11:45 Uhr

ich erschuf Blogbeitrag zum Thema. Es enthält auch einen Link zum Github-Repository mit einem funktionierenden Beispiel.

Der Trick besteht darin, eine Testkonfiguration zu verwenden, bei der Sie die ursprüngliche Spring Bean mit einer gefälschten überschreiben. Sie können verwenden @Primary und @Profile Anmerkungen zu diesem Trick.

Benutzer-Avatar
Sergej Grigorjew

Sie können Bean-Definitionen mit Mocks mit spring-reinject überschreiben https://github.com/sgri/spring-reinject/

Benutzer-Avatar
Rzv Razvan

Ein weiterer Ansatz beim Integrationstest besteht darin, eine neue Konfigurationsklasse zu definieren und diese als Ihre bereitzustellen @ContextConfiguration. In der Konfiguration können Sie Ihre Beans verspotten und Sie müssen auch alle Arten von Beans definieren, die Sie im Testfluss verwenden. Um ein Beispiel zu geben:

@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
 }
}

Benutzer-Avatar
Markus Rotteveel

Für Junit5 können Sie Folgendes verwenden:

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class MytestClass {

@Mock
MyInjectedSevice myInjservice;

@InjectMock
MyService myservice;

}

1216010cookie-checkSpring JUnit: So simulieren Sie eine automatisch verdrahtete Komponente in einer automatisch verdrahteten Komponente

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy