본문 바로가기

Logging/Spring

[문제기록] DataJpaTest 시 NoSuchBeanDefinitionException / UnsatisfiedDependencyException

728x90

새로운 프로젝트에서 Query 가 들어있는 Repository 단을 Test 해야 해서 진행을 해보았다. 일반 Repository 의 모습이라 다음 정도 수준이였다. 

 

 

public interface MemberRepository {
    Optional<Member> findByUsername(String username);
}


@Repository
@RequiredArgsConstructor
public class MemberJpaRepository implements MemberRepository{
    
    private final EntityManager em;
    private final JPAQueryFactory queryFactory;
    
    ...
    @Override
    public Optional<Member> findByUsername(String username){
        return Optional.ofNullable(queryFactory.selectFrom(member)
                    .where(member.username.eq(username))
                    .fetchOne());
    }
}

 

 

그리고 다음과 같이 TC 를 준비해보았다.

 

 

@ActiveProfiles("test")
@DataJpaTest
public class MemberJpaRepositoryTest extends TestObjectCreator { 
    
    @Autowired
    private MemberRepository memberRepository;
    
    @Autowired
    private EntityManager em;
    
    @BeforeEach
    void be(){
        // member 를 미리 넣어주기 위한 가 데이터 생성
       memberRepository.save();
       em.flush();
       em.clear();
    }
    
    ...
}

 

 

일단 TC 할 준비가 되었는지 보기 위해 실행을 시킨 결과, 다음과 같은 에러가 발생하였다. 

 

 

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '~~.MemberRepository': Unsatisfied dependency expressed through field 'memberRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '~~.MemberRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

 

 

사실 해당 에러까지 가기도 전에 갑자기 

 

 

========================== CONDITIONS EVALUATION REPORT============================

 

 

 

이런게 시뻘겋게 떠가지고 매우 당황해서 Context 형성하는데 에러가 있는줄 알고 한참을 해멨다. 역시 에러는 로그를 잘봐야 한다... ㅋㅋㅋㅋㅋ 어쨌든 에러 로그를 보면 다 적혀있기는 하다. 말 그대로

 

 

1번 오류 :  MemberRepository 주입하고 싶은데 넣을 수가 없네?
2번 오류 : MemberRepository 에 충족되지 않은 의존관계가 정의됐네?

 

사실 위에 적혀있는 생성자 주입이 전부이기 때문에, 에러를 보기만 해도 Query DSL 과 연관된 문제임을 바로 알아차릴 수 있어야 하는게 정상이다. 

 

 

다음 블로그를 통해 알고보니 JpaQueryFactory 는 Persistence 가 제어하는 영역이 아니기 때문에 Bean 등록이 되지 않아서 발생하는 문제였다. (@DataJpaTest 는 JPA 관련 Bean 들만 등록한다)  (https://jyami.tistory.com/124)

 

 

 

스프링을 제대로 공부했으면, DI 에 대한 문제정도는 손쉽게 해결할 줄 알아야 한다고 생각한다!!

 

 

드디어 쓴 짤

 

 

난 스프링을 제대로 공부하지 못했나보다. 해결하는데 한참 걸렸다. 반성한다 (뭐 결국 혼자 못하고 열심히 블로그 서치..) 

우선 Test 를 위한 추가적인 Bean 이 필요한 상황임이 자명하니, @TestConfiguration 을 통해 Test 를 위한 추가적인 Bean 을 등록해보자. 

 

 

@TestConfiguration
public class RepositoryTestConfiguration {

    @PersistenceContext
    private EntityManager em;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(em);
    }

}

 

 

인 앱에서 JPAQueryFactory 를 넣을 때와 거의 똑같은 Configuration 을 주는 것이다. 그리고 Repository 에는 당연히 이제 될 줄 알고, 바로 진행을 해보았다. 하지만 결과는 여전히 Fail 이였고, 똑같은 오류를 트레이스 해주고 있었다. 

 

 

사실 이거는 왜이런지 아직도 잘 모르겠다. 좀 더 분석해보고 알게 되면 게시물 업데이트를 해보겠다. 너무 궁금함... 아보니 QueryDslRepositorySupport 같은걸 이용하면 된다는데.. 다른 기술을 또 사용해서 해결하는건 지양해야한다. 

 

 

더 찾아보니 Import Annotation 을 따로 더 해줘야 한다고 한다. 다음과 같이 해줄 수 있겠다. 

 

 

@Import(RepositoryTestConfiguration.class)
@ActiveProfiles("test")
@DataJpaTest
public class MemberJpaRepositoryTest extends TestObjectCreator{
    ...
}

 

 

뭐 여기까진 백번 양보해서 그럴 수 있겠다 싶었다. 근데 이렇게 해도 안되었다. 더 알아보니 Import 해줄 때 사용하는 Repository 도 같이 적어줘야 한다고 한다. 

 

 

@Import({RepositoryTestConfiguration.class, MemberJpaRepository.class})
@ActiveProfiles("test")
@DataJpaTest
public class MemberJpaRepositoryTest extends TestObjectCreator{
    ...
}

 

 

심지어 저게 또 MemberRepository.class 면 또 안된다. RepositoryTestConfiguration 에 Repository 들에 대한 DI 를 새롭게 다 해줘도  (jpaQueryFactory() 를 포함해서) 해결이 되긴 하더라.  결국 위 방식이나 TestConfiguration 에 더 추가해야 하는 방식이나, 

 

 

1. @TestConfiguration 만으로는 원하는 Bean 을 컨테이너에서 찾지 못했다.
2. MemberRepository 의 구현체인 MemberJpaRepository 가 1번으로 인해 @Autowired 에 실패한다.

 

 

왜 그런지는 잘 아직 모르겠다. Test 환경이 동작하는 구조를 조금 더 파헤쳐 봐야 이유를 알 수 있을 것 같다. @TestConfiguration 이 동작하는 원리도.. !!

 

 

.. 이건 꼭 공부해보고  추가해놓겠다. 퇴근해야함.. 

 

 

어쨌든 결론적으로 해결을 구하고자 읽으신 분들은, 아래와 같이 해결하면 됩니다.

 

 

1. @TestConfiguration 으로 JpaQueryFactory Bean 을 추가적으로 넣어줍니다. 
2. @Import() 를 통해 해당 Configuration 파일, 그리고 사용하는 Repository 파일을 직접적으로 넣어서 의존성을 부여해줍니다. 

 

728x90