사지방에서 goorm ide로 개발을 하다보니 생기는 문제점이 몇가지 있다.

 

1) 빌드 속도가 매우 느림

2) 대부분 라이브러리 설치, 설정 방법이 대부분 인텔리제이 기준으로 올라와있음

3) 개별 테스트 불가능, 테스트 실행 속도가 매우 느림

 

이 과정에서 개별 테스트 및 테스트 속도 상승을 위해서 어떻게 해야할까 고민하던 중

통합 테스트는 포기하고, 단위 테스트를 진행하기로 했다.

 

1) Controller 테스트 

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest{
	@Autowired
	MockMvc mvc;
    
	@MockBean
	private UserService userService;
    
	@MockBean
	private UserRepository userRepository;
    
	@Test
	public void 유저_리스트_출력() throws Exception {
		//given
		List<User> userList = new ArrayList<>();
		userList.add(new User("test1", "test1234", "kim"));
		userList.add(new User("test2", "test1234", "park"));
		userList.add(new User("test3", "test1234", "kim"));
        
		Pageable pageable = PageRequest.of(0,20);
        
		Page<User> pageResult = new PageImpl<>(userList, pageable, 3);
        
		given(userService.findAllBySearch(any(Pageable.class),any(),any())).willReturn(pageResult);
        
		//when
		mvc.perform(get("/users"))
		//then
		.andExpect(status().isOk())
		.andExpect(jsonPath("$.data[0].accountId").value("test1"))
		.andExpect(jsonPath("$.data[1].accountId").value("test2"))
		.andExpect(jsonPath("$.data[2].accountId").value("test3"));
	}
}

WebmvcTest를 사용하기로 했다.

Junit4에선 @RunWith이 필요하다고 해서 추가했다.

 

service 단에서의 응답을 @MockBean과 given을 이용해서 대체했다.

 

2)Service 테스트

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest{
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserServiceImpl userService;
    
    @Test
    public void 유저_단건_조회(){
        //given
        User user = new User("test1", "test1234", "kim");
        given(userRepository.findById(any(Long.class))).willReturn(Optional.of(user));
        Long userId = 1L;
        
        //when
        User result = userService.findOne(userId);
        
        //then
        assertThat(result.getAccountId()).isEqualTo("test1");
    }
}

service에서는 Mockito를 사용했다.

@Mock을 이용해 가짜 repository를 만들고

@InjectMocks를 이용해 userService 객체에 만들어놓은 Mock 객체를 주입했다.

 

이때 스프링을 이용해서 하는 테스트가 아니기 때문에 service가 인터페이스라면 작동하지 않는다.

실제 구현되는 serviceImpl 객체를 이용해서 테스트해야한다.

 

마찬가지로 given을 이용해 repository의 응답을 대체했다.

 

3) Repository 테스트

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(AppConfig.class)
public class UserRepositoryTest{
    
    
    @Autowired
    private UserRepository userRepository;
    
    @Test //유저 생성
    public void test_save(){
        //given
        User user = new User("test1", "test1234!", "kim");
        //when
        User saveUser = userRepository.save(user);
        
        //then
        assertThat(saveUser.getAccountId()).isEqualTo("test1");
    }
 }

DataJpaTest를 사용했다.

이때 Auditing, queryDSL등을 활용하기 위해 AppConfig 클래스를 따로 만들어줬으므로

테스트 시에도 활용하기 위해 @Import 를 통해 불러와줘야한다.

또 테스트용 DB설정을 따로 하지 않았으므로

@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)를 사용해준다.

 

근데 테스트용 Replace.NONE는 미리 설정해놓은 local DB를 그대로 사용하는데

테스트용 데이터와 기존 데이터가 겹치는 문제가 생길 수 있다.

 

그래서 mysql에서 테스트용 db를 새로 만들고 test 폴더 안에 application.yml 파일을 새로 만들어서 설정해줬다.

 

그 외 겪었던 오류와 해결법

 

queryDSL 설정법

build.gradle 에 queryDSL관련 설정 추가 (src/main/generated 폴더 안으로 Q객체 생성되도록 설정)

// querydsl 추가
ext.querydslVersion = "4.4.0"

def querydslSrcDir = 'src/main/generated'
clean {
    delete file(querydslSrcDir)
}
tasks.withType(JavaCompile) {
    options.generatedSourceOutputDirectory = file(querydslSrcDir)
}
sourceSets {
    main.java.srcDir querydslSrcDir
}


dependencies {
    //querydsl 추가
    implementation "com.querydsl:querydsl-jpa:${querydslVersion}"
    annotationProcessor(
        "jakarta.persistence:jakarta.persistence-api",
        "jakarta.annotation:jakarta.annotation-api",
        "com.querydsl:querydsl-apt:${querydslVersion}:jpa"
    )
}

AppConfig 파일 추가 (메인클래스 위치에)

package project;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.PersistenceContext;

import javax.persistence.EntityManager;

@Configuration
@RequiredArgsConstructor
public class AppConfig {
    
    @PersistenceContext
    private final EntityManager em;

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

}

EntityManger은 왜 설정해줬는지 기억이 안나는데

아마 respository 테스트 할때 영속성 컨텍스트 주입을 위해서였던 것 같다.

 

 

Swagger 설정

application.yml에 설정 추가 (packages-to-scan에 스캔할 컨트롤러가 있는 패키지 입력)

# Swagger springdoc-ui Configuration
springdoc:
  packages-to-scan: project.controller
  default-consumes-media-type: application/json;charset=UTF-8
  default-produces-media-type: application/json;charset=UTF-8
  swagger-ui:
    path: swagger-ui.html
    disable-swagger-default-url: true
    display-request-duration: true
    operations-sorter: alpha

 

OpenApiConfig 생성 혹은 AppConfig에 설정 추가

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

/**
 * Swagger springdoc-ui 구성 파일
 */
@Configuration
@EnableJpaAuditing
public class OpenApiConfig {
    @Bean
    public OpenAPI openAPI() {
        Info info = new Info()
                .title("도마잎 API Document")
                .version("v0.0.1")
                .description("API 명세서입니다.");
        return new OpenAPI()
                .components(new Components())
                .info(info);
    }
}

 

goorm ide 링크가 https라서 문제가 발생하는 경우

Application.java 에 url 설정 추가

@OpenAPIDefinition(servers = {@Server(url = "https로 시작하는 url", description = "Default url")})

 

+ Recent posts