source

응용 프로그램을 시작하기 전에 @MockBean 구성 요소 구성

factcode 2023. 3. 25. 11:56
반응형

응용 프로그램을 시작하기 전에 @MockBean 구성 요소 구성

Spring Boot 1.4.2 어플리케이션이 있습니다.기동시에 사용되는 코드는, 다음과 같습니다.

@Component 
class SystemTypeDetector{
    public enum SystemType{ TYPE_A, TYPE_B, TYPE_C }
    public SystemType getSystemType(){ return ... }
}

@Component 
public class SomeOtherComponent{
    @Autowired 
    private SystemTypeDetector systemTypeDetector;
    @PostConstruct 
    public void startup(){
        switch(systemTypeDetector.getSystemType()){   // <-- NPE here in test
        case TYPE_A: ...
        case TYPE_B: ...
        case TYPE_C: ...
        }
    }
}

시스템 유형을 결정하는 컴포넌트가 있습니다.이 구성 요소는 다른 구성 요소에서 시작할 때 사용됩니다.생산에서는 모든 것이 잘 작동합니다.

1.Spring 1.4를 하겠습니다.@MockBean.

테스트는 다음과 같습니다.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyWebApplication.class, webEnvironment = RANDOM_PORT)
public class IntegrationTestNrOne {
    @MockBean 
    private SystemTypeDetector systemTypeDetectorMock;

    @Before 
    public void initMock(){
       Mockito.when(systemTypeDetectorMock.getSystemType()).thenReturn(TYPE_C);
    }

    @Test 
    public void testNrOne(){
      // ...
    }
}

기본적으로 조롱은 잘 통한다. ''이 되며 TypeDetectorMock하면 'TypeDetectorMock'이 사용됩니다.getSystemType->TYPE_C이 반환됩니다.

문제는 애플리케이션이 부팅되지 않는다는 것입니다.현재 스프링 작동 순서는 다음과 같습니다.

  1. create all Mocks (설정하지 않으면 모든 메서드가 null을 반환함)
  2. 응용 프로그램을 시작하다
  3. call @Before-methods(모크가 설정되는 장소)
  4. 테스트 개시

문제는 어플리케이션이 초기화되지 않은 모의로 시작된다는 것입니다.그래서 ''에 콜'은getSystemType()manager가 됩니다.

질문입니다.애플리케이션 기동 전에 어떻게 모크를 설정할 수 있습니까?

편집: 같은 문제를 안고 있는 사람이 있는 경우, 1개의 회피책은@MockBean(answer = CALLS_REAL_METHODS)이렇게 하면 실제 컴포넌트가 호출되어 시스템이 부팅됩니다.부팅 후 모의 동작을 변경할 수 있습니다.

을 mock보다 먼저 .@MockBean도입되었습니다.@Primary콘텍스트에서 원래 콩을 대체할 콩입니다.

@SpringBootTest
class DemoApplicationTests {

    @TestConfiguration
    public static class TestConfig {

        @Bean
        @Primary
        public SystemTypeDetector mockSystemTypeDetector() {
            SystemTypeDetector std = mock(SystemTypeDetector.class);
            when(std.getSystemType()).thenReturn(TYPE_C);
            return std;
        }

    }

    @Autowired
    private SystemTypeDetector systemTypeDetector;

    @Test
    void contextLoads() {
        assertThat(systemTypeDetector.getSystemType()).isEqualTo(TYPE_C);
    }
}

★★@TestConfiguration이며 이테스트에서만 됩니다. 수 동작의 @Before콩을 초기화하는 방법으로 이동해야 합니다.

이렇게 고칠 수 있었어요.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyWebApplication.class, webEnvironment = RANDOM_PORT)
public class IntegrationTestNrOne {
    // this inner class must be static!
    @TestConfiguration
    public static class EarlyConfiguration {
       @MockBean 
       private SystemTypeDetector systemTypeDetectorMock;

       @PostConstruct 
       public void initMock(){
          Mockito.when(systemTypeDetectorMock.getSystemType()).thenReturn(TYPE_C);
       }
    }

    // here we can inject the bean created by EarlyConfiguration
    @Autowired 
    private SystemTypeDetector systemTypeDetectorMock;

    @Autowired
    private SomeOtherComponent someOtherComponent;

    @Test 
    public void testNrOne(){
       someOtherComponent.doStuff();
    }
}

다음의 트릭을 사용할 수 있습니다.

@Configuration
public class Config {

    @Bean
    public BeanA beanA() {
        return new BeanA();
    }

    @Bean
    public BeanB beanB() {
        return new BeanB(beanA());
    }
}

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {TestConfig.class, Config.class})
public class ConfigTest {

    @Configuration
    static class TestConfig {

        @MockBean
        BeanA beanA;

        @PostConstruct
        void setUp() {
            when(beanA.someMethod()).thenReturn(...);
        }
    }
}

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★spring-boot-2.1.9.RELEASE

은 봄보다 먼저 된다.@Before되지 않도록 .@PostConstruct주석이 달린 메서드가 실행됩니다.

'은 '을 해보겠습니다.@LazySystemTypeDetector★★★★★★★★★★★★★★를 사용해 주세요.SystemTypeDetector에 따라서, 「」에서는이 할 수 것에 .@PostConstruct또는 동등한 후크.

의존관계를 자동화하는 방식 때문인 것 같아요.이것을 봐 주세요(특히, 「Fix #1: 설계를 해결하고 의존 관계를 표시」에 관한 부분).이 방법을 사용하면, 유저와 유저에 의한@PostConstruct대신 컨스트럭터를 사용합니다.

사용하고 있는 것은, 유닛 테스트에 적합합니다.

org.mockito.Mockito#when()

콘텍스트가 정리되어 있을 때는, 다음의 방법으로 봄콩을 조롱해 주세요.

org.mockito.BDDMockito#given()

@SpyBean을 사용하는 경우 다른 구문을 사용해야 합니다.

willReturn(Arrays.asList(val1, val2))
        .given(service).getEntities(any());

언급URL : https://stackoverflow.com/questions/40563409/configure-mockbean-component-before-application-start

반응형