programing

모의 서비스/구성요소를 사용한 스프링 부트 통합 테스트

bestprogram 2023. 7. 1. 09:04

모의 서비스/구성요소를 사용한 스프링 부트 통합 테스트

상황문제:Spring Boot에서 하나 이상의 모의 클래스/빈을 응용 프로그램에 주입하여 통합 테스트를 수행하려면 어떻게 해야 합니까?StackOverflow에 대한 몇 가지 답변이 있지만 SpringBoot 1.4 이전의 상황에 초점을 맞추거나 저에게 적합하지 않습니다.

배경은 아래 코드에서 Settings 구현이 타사 서버 및 기타 외부 시스템에 의존한다는 것입니다.설정의 기능은 이미 단위 테스트에서 테스트되었으므로 전체 통합 테스트의 경우 이러한 서버 또는 시스템에 대한 종속성을 모의 분석하고 더미 값만 제공하고자 합니다.

MockBean은 기존의 모든 빈 정의를 무시하고 더미 개체를 제공하지만 이 개체는 이 클래스를 주입하는 다른 클래스에서 메서드 동작을 제공하지 않습니다.@Before 방법을 사용하여 테스트 전 동작을 설정해도 주입된 개체에 영향을 주지 않거나 AuthenticationService와 같은 다른 응용 프로그램 서비스에 주입되지 않습니다.

질문:애플리케이션 컨텍스트에 내 의견을 주입하려면 어떻게 해야 합니까?내 테스트:

package ch.swaechter.testapp;

import ch.swaechter.testapp.utils.settings.Settings;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.junit4.SpringRunner;

@TestConfiguration
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyApplication.class})
public class MyApplicationTests {

    @MockBean
    private Settings settings;

    @Before
    public void before() {
        Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret");
    }

    @Test
    public void contextLoads() {
        String applicationsecret = settings.getApplicationSecret();
        System.out.println("Application secret: " + applicationsecret);
    }
}

그리고 조롱당한 클래스를 사용해야 하지만 이 조롱당한 클래스를 받지 못하는 서비스를 따라갑니다.

package ch.swaechter.testapp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AuthenticationServiceImpl implements AuthenticationService {

    private final Settings settings;

    @Autowired
    public AuthenticationServiceImpl(Settings settings) {
        this.settings = settings;
    }

    @Override
    public boolean loginUser(String token) {
        // Use the application secret to check the token signature
        // But here settings.getApplicationSecret() will return null (Instead of Application Secret as specified in the mock)!
        return false;
    }
}

조롱된 동작을 지정하기 전에 설정 개체를 사용하는 것 같습니다.당신은 뛰어야 합니다.

Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret");

구성 설정 중에 표시됩니다.테스트용으로만 특수 구성 클래스를 만들 수 있습니다.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyApplication.class, MyApplicationTest.TestConfig.class})
public class MyApplicationTest {

    private static final String SECRET = "Application Secret";

    @TestConfiguration
    public static class TestConfig {
        @Bean
        @Primary
        public Settings settingsBean(){
            Settings settings = Mockito.mock(Settings.class);
            Mockito.when(settings.getApplicationSecret()).thenReturn(SECRET);
            Mockito.doReturn(SECRET).when(settings).getApplicationSecret();
            return settings;
        }

    }

.....

}  

또한 조롱에는 다음 표기법을 사용할 것을 권장합니다.

Mockito.doReturn(SECRET).when(settings).getApplicationSecret();

설정을 실행하지 않습니다.:getApplicationSecret

@MockBean으로 필드에 주석을 달면 spring은 주석이 달린 클래스의 모의실험을 만들고 이를 사용하여 응용프로그램 컨텍스트의 모든 빈을 자동 배선합니다.

당신은 당신 자신을 조롱해서는 안 됩니다.

 Settings settings = Mockito.mock(Settings.class);

이는 두 번째 모의실험을 만들어 설명된 문제로 이어질 수 있습니다.

솔루션:

@MockBean
private Settings settings;

@Before
public void before() {
Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret");
}

@Test
public void contextLoads() {
    String applicationsecret = settings.getApplicationSecret();
    System.out.println("Application secret: " + applicationsecret);
}

언급URL : https://stackoverflow.com/questions/42641853/spring-boot-integration-testing-with-mocked-services-components