bestsource

단위시험환경에서 스프링콩 재정립

bestsource 2023. 10. 16. 21:57
반응형

단위시험환경에서 스프링콩 재정립

우리는 Spring을 응용 목적으로 사용하고 있고, Spring Testing framework를 단위 테스트에 사용하고 있습니다.그러나 작은 문제가 있습니다. 응용 프로그램 코드가 클래스 경로의 위치 목록(XML 파일)에서 Spring 응용 프로그램 컨텍스트를 로드합니다.하지만 우리는 유닛 테스트를 실행할 때 본격적인 구현 수업 대신 일부 봄 콩을 모의로 만들기를 원합니다.또한 일부 단위 테스트의 경우 일부 콩이 모의실험이 되기를 원하며 다른 단위 테스트의 경우 다른 콩이 모의실험이 되기를 원합니다. 응용 프로그램의 여러 계층을 테스트하는 것처럼 말입니다.

이 모든 것은 애플리케이션 컨텍스트의 특정 빈을 다시 정의하고 원하는 경우 컨텍스트를 새로 고치고 싶다는 것을 의미합니다.이 작업을 수행하는 동안 원본 XML 콩 정의 파일 하나(또는 여러 개)에 있는 콩의 일부만 재정의하려고 합니다.나는 그것을 하는 쉬운 방법을 찾을 수가 없습니다.스프링은 항상 유닛 테스트에 적합한 프레임워크로 간주되기 때문에 여기서 제가 놓친 부분이 있을 것입니다.

어떻게 하는지 알고 계십니까?

감사합니다!

입니다를 합니다.TestClass스프링 빈.xml 위치에 대한 몇 가지 쉬운 규칙:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath*:spring/*.xml",
    "classpath*:spring/persistence/*.xml",
    "classpath*:spring/mock/*.xml"})
@Transactional
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class})
public abstract class AbstractHibernateTests implements ApplicationContextAware {

    /**
     * Logger for Subclasses.
     */
    protected final Logger log = LoggerFactory.getLogger(getClass());

    /**
     * The {@link ApplicationContext} that was injected into this test instance
     * via {@link #setApplicationContext(ApplicationContext)}.
     */
    protected ApplicationContext applicationContext;

    /**
     * Set the {@link ApplicationContext} to be used by this test instance,
     * provided via {@link ApplicationContextAware} semantics.
     */
    @Override
    public final void setApplicationContext(
            final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

경우.mock-bean.xml "든 짜"다를 .bean.xml"정상" 위치에 있는 파일 - 정상 위치가 다를 수 있습니다.

하지만… 애플리케이션이 오래되면 문제를 추적하는 것이 어렵기 때문에, 저는 결코 가짜 콩과 가짜가 아닌 콩을 섞지 않을 것입니다.

봄을 시험 친화적이라고 표현하는 이유 중 하나는 단원 시험에서 새로운 것이나 모의 시험을 하는 것이 쉬울 수 있기 때문입니다.

또는 다음 설정을 성공적으로 사용하여 고객님이 원하는 것과 매우 유사하다고 생각합니다. 강력하게 권장합니다.

다른 맥락에서 다른 구현이 필요한 모든 콩의 경우 주석 기반 배선으로 전환합니다.나머지는 그대로 두셔도 됩니다.

다음 주석 집합 구현

 <context:component-scan base-package="com.foobar">
     <context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>
     <context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
 </context:component-scan>

그런 다음 @Repository를 사용한 실시간 구현, @StubRepository를 사용한 스터브 구현, @TestScopedComponent를 사용한 유닛 테스트 고정 장치에만 존재해야 하는 코드에 주석을 달게 됩니다.주석이 몇 개 더 필요할 수도 있지만, 이는 좋은 시작입니다.

spring.xml이 많은 경우 기본적으로 component-scan 정의만 포함하는 spring xml 파일을 몇 개 새로 만들어야 할 것입니다.보통 이 파일들을 일반 @ContextConfiguration 목록에 추가합니다.그 이유는 여러분이 자주 다른 형태의 컨텍스트 스캔을 하게 되기 때문입니다. (나를 믿으세요, 웹 테스트를 하는 경우 최소 1개의 주석을 추가할 이고, 이는 4개의 관련된 조합을 만드는 것입니다.)

그럼 당신은 기본적으로

@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)

이 설정에서는 스터브/라이브 데이터의 조합을 번갈아 사용할 수 없습니다.우리는 이것을 시도했고, 그것이 제가 추천하고 싶지 않은 혼란을 초래했다고 생각합니다 ;) 우리는 전체 스텁 세트 또는 전체 라이브 서비스 세트에 유선을 연결합니다.

우리는 보통 의존성이 상당히 큰 기니어 물질을 테스트할 때 주로 자동 배선 스터브 의존성을 사용합니다.코드의 청정 지역에서는 더 정기적인 단위 테스트를 사용합니다.

당사 시스템에는 컴포넌트 스캔을 위한 다음과 같은 xml 파일이 있습니다.

  • 정기적인 웹 제작을 위해
  • 스텁으로만 웹을 시작하는 경우
  • 통합 테스트를 위해(조인트 단위)
  • 유닛 테스트용(조인트 단위
  • 셀레늄 웹 테스트용(조인트 단위)

이는 애플리케이션을 시작할 수 있는 시스템 전체 구성이 총 5가지라는 것을 의미합니다.우리는 주석만 사용하기 때문에, 스프링은 우리가 원하는 단위 테스트도 자동으로 배선할 수 있을 정도로 빠릅니다.이것이 전통적이지 않다는 것을 알지만, 정말 훌륭합니다.

통합 테스트는 풀 라이브 셋업과 함께 실행되며, 한 두 번은 정말 실용적이기로 결심했고 5개의 라이브 배선과 단일 모의 테스트를 원합니다.

public class HybridTest {
   @Autowired
   MyTestSubject myTestSubject;


   @Test
   public void testWith5LiveServicesAndOneMock(){
     MyServiceLive service = myTestSubject.getMyService();
     try {
          MyService mock = EasyMock.create(...)
          myTestSubject.setMyService( mock);

           .. do funky test  with lots of live but one mock object

     } finally {
          myTestSubject.setMyService( service);
     }


   }
}

테스트 퓨리스트들이 이 일 때문에 온 몸이 달아오를 거라는 걸 알아요.하지만 가끔은 그 대안이 정말로 추악할 때 매우 우아하다는 것이 밝혀지는 매우 실용적인 해결책일 뿐입니다.다시 말하지만, 그것은 보통 그 근처 지역에 있습니다.

@InjectedMock 주석이 있는자습서 보기

시간을 많이 절약할 수 있었습니다.당신은 그냥 사용합니다.

@Mock
SomeClass mockedSomeClass

@InjectMock
ClassUsingSomeClass service

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

당신의 모든 문제가 해결될 겁니다.모키토는 스프링 의존성 주사를 모키로 대체할 것입니다.그냥 제가 직접 사용해봤는데 효과가 좋네요.

여기에는 매우 복잡하고 강력한 솔루션이 몇 가지 나열되어 있습니다.

하지만 Stas가 요청한 것을 달성하기 위해 멀고 훨씬 간단한 방법이 있습니다. 테스트 방법에는 코드 한 줄 외에 어떤 것도 수정하지 않습니다.장치 테스트와 스프링 통합 테스트, 자동 배선 종속성, 개인 필드 및 보호 필드에 대해 동일하게 작동합니다.

여기 있습니다.

junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);

조회가 전혀 필요 없도록 단위 테스트를 작성할 수도 있습니다.

@ContextConfiguration(locations = { "classpath:/path/to/test-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyBeanTest {

    @Autowired
    private MyBean myBean; // the component under test

    @Test
    public void testMyBean() {
        ...
    }
}

이를 통해 실제 구성 파일과 테스트 구성 파일을 쉽게 혼합하고 일치시킬 수 있습니다.

예를 들어, 최대 절전 모드를 사용할 때 sessionFactory가 하나의 구성 파일에 있을 수 있고(테스트와 메인 앱에서 모두 사용할 수 있음), dataSource가 다른 구성 파일에 있을 수 있습니다(하나는 DriverManagerDataSource를 사용하여 메모리 내 DB를 만들고 다른 하나는 JNDI-lookup을 사용할 수 있음).

하지만, @cletus의 경고에 꼭 주의하세요 ;-)

간단합니다. 유닛 테스트에 맞춤형 애플리케이션 컨텍스트를 사용하거나, 전혀 사용하지 않고 수동으로 콩을 만들어 주입합니다.

시험 범위가 너무 넓을 수도 있는 것 같네요.유닛 테스트는 유닛 테스트에 관한 것입니다.봄콩은 유닛의 아주 좋은 예입니다.이를 위해 전체 애플리케이션 컨텍스트가 필요하지는 않습니다.유닛 테스트가 수백 개의 빈, 데이터베이스 연결 등이 필요할 정도로 수준이 높은 경우, 다음 변경 사항을 중단하고 유지보수하기가 어렵고 실제로 많은 가치를 추가하지 못하는 매우 취약한 유닛 테스트가 있다는 것을 알게 되었습니다.

테스트 앱 컨텍스트에서 가져오기 기능을 사용하여 prod bean을 로드하고 원하는 것을 재정의할 수 있습니다.예를 들어, 내 prod 데이터 소스는 보통 JNDI lookup을 통해 획득하지만, 테스트할 때는 DriverManager 데이터 소스를 사용하기 때문에 테스트를 위해 앱 서버를 시작할 필요가 없습니다.

저는 더피모의 대답에 대해 많은 평판을 얻을 수는 없지만, 저는 그저 그의 대답이 저에게 "올바른" 대답이라고 말하고 싶었을 뿐입니다.

사용자 지정 applicationContext.xml을 사용하여 단위 테스트의 설정에서 FileSystemXmlApplicationContext를 인스턴스화합니다.사용자 정의 xml에서 맨 위에 duffymo가 나타내는 대로 수행합니다.그런 다음 가짜 콩, JNDI가 아닌 데이터 소스 등을 신고하면 해당 ID가 수입에 신고된 것을 무시됩니다.

나에게는 꿈같은 일을 했습니다.

테스트 컨텍스트를 사용할 필요는 없습니다(XML이나 Java 기반은 중요하지 않습니다).스프링부트 1.4 이후로 스프링빈의 조롱과 스파이에 대한 네이티브 지원을 도입한 새로운 주석이 있습니다.

콩에 예선전을 사용할 수도 있겠군요?당신은 조롱하고 싶은 콩을 별도의 응용프로그램 컨텍스트에서 재정의하고 "테스트"라는 수식어로 라벨을 붙입니다.단위 테스트에서 콩을 배선할 때 항상 "테스트"라는 수식어를 지정하여 모형을 사용합니다.

저도 같은 일을 하고 싶고, 우리는 그것이 필수적이라고 생각하고 있습니다.

우리가 사용하는 현재의 메커니즘은 상당히 수동적이지만 작동합니다.

예를 들어, Y형 콩을 무시하고 싶다고 합시다.우리가 하는 일은 우리가 인터페이스를 구현하는 데 필요한 의존성을 가진 모든 콩입니다 - "IHASY".이 인터페이스는

interface IHasY {
   public void setY(Y y);
}

그 다음 테스트에서는 util method라고 부릅니다.

 public static void insertMock(Y y) {
        Map invokers = BeanFactory.getInstance().getFactory("core").getBeansOfType(IHasY.class);
        for (Iterator iterator = invokers.values().iterator(); iterator.hasNext();) {
            IHasY invoker = (IHasY) iterator.next();
            invoker.setY(y);
        }
    }

저는 단지 이 새로운 종속성을 주입하기 위해 전체 xml 파일을 만들고 싶지 않으며, 그것이 제가 이것을 좋아하는 이유입니다.

xml config 파일을 생성할 의사가 있다면 mock bean으로 새 공장을 만들고 기본 공장을 이 공장의 모체로 만드는 방법이 있습니다.그럼 새로 생긴 어린이 공장에서 모든 콩을 실어가는지 확인하세요.이 작업을 수행할 때, 콩 ID가 동일할 때 하위 공장은 모 공장의 콩을 덮어씁니다.

만약 제 시험에서, 제가 프로그램적으로 공장을 만들 수 있다면, 그것은 굉장할 것입니다.xml을 사용해야 하는 것은 너무 번거로울 뿐입니다.코드로 그 아이 공장을 만들려고 합니다.그러면 각 테스트에서 원하는 방식으로 공장을 구성할 수 있습니다.그런 공장이 안 될 이유가 없습니다.

스프링 리젝트는 콩을 조롱박으로 대체하기 위해 고안되었습니다.

OP 이후로 이것은 등장했습니다: Springockito

언급URL : https://stackoverflow.com/questions/565334/spring-beans-redefinition-in-unit-test-environment

반응형