매번 단위테스트가 현재 프로젝트에 대해 얼마나 커버를 하는지 메서드 line 단위로 확인을 하고 싶어 code coverage에 대해 알아보게 되었습니다.
그 중에서도 다른 레퍼런스에 비해 많이 검색되고, 자체 docs를 잘 관리하고 있는 Codecov 를 최종적으로 선택하게 되었습니다.
PR에 보기 편하게 report를 해주고, Github Actions와 쉽게 연동할 수 있도록 기능을 제공하고 있었기 때문입니다.
Codecov 회원가입
깃허브 레파지토리와 연동이 필요하다면 반드시 깃허브 계정으로 로그인이 되어야 합니다.
깃허브 계정으로 소셜로그인을 했다면, 다음 창으로 현재 내 깃허브 레파지토리에 접근하겠다는 Access Authorize 관련 창이 뜨게 됩니다. 혹시 슬랙과 깃허브를 연동해보셨다면 뜨는 깃허브와의 연결 화면입니다. (처음 연결시킬 때 캡처를 남기지 않아 사진이 없네요..ㅠㅠ)
Codecov <-> Github Repository
로그인을 한다면 현재 내 Organization과 개인 레파지토리 정보를 불러오게 됩니다(단, Private 레파지토리는 불러오지 않음)
저 같은 경우 처음 로그인 했을 때 연동이 필요한 레파지토리가 뜨지 않은 줄 알고 당황했었는데요, 현재 밑에 보이는 캡처본은 Enabled 상태만을 보여주고 있습니다. 아직 Codecov와 연결을 위한 셋업을 하지 않았기 때문에 오른쪽 위에 보이는 Not yet set up을 클릭해 연결할 레파지토리를 선택합니다.
이 때 연결을 할 때에도 Codecov가 해당 레파지토리에 대해 Read 하고, report 결과를 레파지토리에 보여줄 수 있도록 Write 권한을 설정하는 화면이 떴었습니다.(이거도 캡처를 못하고...) 이미 권한은 자동으로 선택이 되어 있었고, 어떤 레파지토리에 해당 권한을 줄 건지 선택만 하고 OK를 클릭하면 되는 간단한 작업이었습니다.
build.gradle jacoco 의존성 추가하기
테스트 커버리지를 report하는 여러 방식 중에 jacoco라는 측정 툴이 있습니다. Java 또는 Kotlin 코드로 작성된 Gradle 프로젝트에 대한 코드 커버리지를 측정하는 도구인데요, html/xml 등의 여러 파일형식으로 report를 쉽게 보고, Codecov에 시각화 할 수 있도록 전송도 가능한 기능이 있어 사용하게 되었습니다.
우아한 형제들 기술블로그에 해당 내용에 대해 자세하게 나와있으니 참고하면 좋을 것 같습니다.
https://techblog.woowahan.com/2661/
plugins {
id 'org.springframework.boot' version '2.4.11-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'jacoco' # jacoco 플러그인 추가
}
group = 'com.test'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
jacoco {
toolVersion = "0.8.7"
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
compile group: 'org.springframework', name: 'spring-test'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude module: 'junit'
}
testImplementation('org.junit.jupiter:junit-jupiter-api')
testImplementation 'io.github.javaunit:autoparams:0.2.8'
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine')
}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
}
jacocoTestReport {
executionData(fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec"))
reports {
html.enabled true
xml.enabled true
csv.enabled false
}
}
(이거보다 의존성이 훨씬 많지만, 너무 길어져서 일부는 생략했습니다.)
플러그인에 jacoco 를 추가해주고, junit test가 수행될 때 같이 돌 수 있도록 finalizedBy를 넣어 줍니다. jacocoTestReport는 바이너리 커버리지 결과를 사람이 읽기 좋은 형태의 리포트로 저장합니다. html 파일로 생성해 사람이 쉽게 눈으로 확인할 수도 있고, SonarQube 등으로 연동하기 위해 xml, csv 같은 형태로도 리포트를 생성할 수 있습니다. 저는 csv 파일은 사용하지 않을 것 같아 커스텀하게 false로 지정하고, 나머지는 Codecov에 전송할 때 필요한 파일들의 확장자이기 때문에 true로 설정해주었습니다.
codecov.yml
해당 파일은, Codecov에서만 읽어가는 파일입니다. 꼭 필요한 파일은 아니지만 커스텀하게 지정하고싶은게 있다면 반드시 생성해야하는 파일입니다. 저희는 PR에 report를 날려주어야 하기 때문에 해당 파일로 조작이 필요하였습니다. 다른 기능은 넣지 않았고 간단히 CI 통과여부와 PR comments 를 넣어 주었습니다. 해당 파일은 프로젝트 root 디렉토리에 추가해주어야 합니다.
codecov:
require_ci_to_pass: yes
comment:
layout: "reach,diff,flags,files,footer"
behavior: default
require_changes: false
branches:
- develop
- main
Github Actions Workflow yml 파일 작성
이제, 새로운 기능을 만들고 PR을 올렸을 때 해당 코드의 테스트 커버리지를 측정하기 위해서 CI와 Unit test를 수행할 때 같이 깃허브 액션으로 실행되도록 Workflow를 하나 생성해주도록 합니다.
name: Code Coverage sample
on:
push:
branches:
- 'develop'
- 'main'
pull_request:
branches:
- 'develop'
- 'main'
jobs:
code-coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Test with Gradle
run: ./gradlew build jacocoTestReport
- name: Report to CodeCov
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./build/reports/jacoco/test/jacocoTestReport.xml
간단히, 이전 CI 작업과 비슷합니다만 마지막에 Report to Codecov 라는 작업이 낯설 것이라고 생각합니다. token의 경우 Codecov에 연동이 필요한 레파지토리를 클릭하면 바로 Upload token 이라고 하면서 뜨는 화면이 있습니다. 헤당 토큰은 깃허브 액션이 수행될 때 환경변수 값으로 주입될 수 있도록 Github secrets에 추가하도록 합니다.
그리고 마지막으로
file: ./build/reports/jacoco/test/jacocoTestReport.xml
이 부분은 뭐지? 하실 수 있을 것 같습니다. codecov가 시각화 할 수 있는 report 파일을 의미하며 프로젝트 빌드와 테스트 수행 시 gradle build 결과물 내에서 확인할 수 있습니다.
해당 디렉토리대로 잘 입력해주어야 테스트 커버리지 측정결과가 제대로 Codecov에 전달이 됩니다.
이제 Workflow를 실행시켜 보도록 합니다!
이렇게 리포트가 잘 쓰여지는 것을 확인할 수 있습니다!! 👏👏👏👏👏
Codecov 내에서도 이렇게 각 파일별로 테스트커버리지가 얼마나 되었는지 확인할 수 있습니다. 저희는 Service layer에 대해서만 단위테스트를 진행해서.. 다른곳에서는 비교적 테스트 커버리지가 낮은 것으로 보였습니다.
작업을 진행한 PR을 같이 첨부하니 참고용으로 같이 봐주시면 좋을 것 같습니다~!🥳🥳👀
https://github.com/depromeet/bread-map-backend/pull/133
'개발이야기' 카테고리의 다른 글
mac M1에서 메모리 힙 덤프 떠서 분석하기 (2) | 2023.12.10 |
---|---|
Git flow 이해하기 (0) | 2022.05.10 |
Funtional Programming은 어떻게 가능하게 되었을까? (0) | 2021.11.15 |
AWS S3 이미지 업로드 Spring으로 사용해보기 (2) | 2021.11.14 |
Junit 단위테스트에서 AutoParams 사용해보기(feat. TDD) (0) | 2021.11.06 |