정적 분석 VS 동적 분석
구분 | 정적 분석 | 동적 분석 |
분석 대상 | 소스 코드 또는 컴파일된 바이너리 | 프로그램 실행 환경 |
테스트 범위 | 소스 코드의 모든 부분 | 실행 가능한 경로 |
활용 | 코드 상의 문제나 실수를 찾기 | 테스트, 모니터링 |
- 정적 분석은 주로 개발 단계에서 코드의 구조적 문제를 파악할 때 사용한다.
- 동적 분석은 주로 테스트나 모니터링에 사용한다.
Sonarqube
- 정적 분석을 도와주는 대표적인 도구
- 프로젝트 코드 품질 측정
- 프로젝트 코드의 품질 정보 측정
- 빌드 및 통합 후 품질 변화 측정
- 폴리그랏 언어별 Rule 지원
- Java, GO 언어 등 언어별 Rule 지원
- Jacoco 등 분석 플러그인 지원
- Quality Profiles 관리
- 분석 Ruleset 정의 및 적용
- Ruleset 기반 Profile 구성
- 자신의 프로젝트에 맞는 코드 검사 Rule을 설정할 수 있다.
- Quality Gates 설정
- 다수 그룹의 품질 요구사항 설정
- 다수 항목별 품질 요구사항 설정
- 품질 기준을 설정하여 만족하는지 확인 가능
- A~D 등급으로 나타난다.
- DevOps 통합 가능
- CI 도구와 통합, DevOps 방식 관리 가능
Jacoco
- Java Code Coverage
- 자바 소스 파일의 코드 커버리지 제공
- 테스트 케이스에 의한 테스트 수 측정
- Instruction Coverage
- 코드 실행량 측정 커버리지
- Branch Coverage
- if나 swtich 문의 분기 확인
- 실행된 것과 실행되지 않은 부분 측정
- Cyclomatic Complxity
- function 테스트 시 최소 경로 정보
- 모든 코드를 커버하기 위한 테스트 수
- 자바 소스 파일의 코드 커버리지 제공
실습
환경: AWS EC2 ubuntu 20.04 + Docker + AWS ECR
1. AWS EC2에 SonarQube 설치
- docker run -d -p 9000:9000 sonarqube:latest 명령어를 사용해서 SonarQube를 설치한다.
2. AWS EC2 인바운드 규칙 설정
- AWS EC2의 보안 -> 인바운드 규칙 설정에서 9000번 포트를 허용한다.
3. SonarQube 접속
- 브라우저에서 [AWS EC2 퍼블릭 IPv4 DNS]:9000을 입력하여 SonarQube에 접속하면 로그인 창이 뜬다.
- 최초 계정은 admin/admin으로 다음을 입력하고 로그인을 진행하고 새로운 패스워드로 변경한다.
4. Test 계정 생성하기
- SonarQube 메인 페이지에서 Administration 버튼을 클릭한다.
- Security -> Users를 클릭한다.
- Test 계정을 생성하기 위해 Create User 버튼을 클릭한다.
- 항목을 채워주고 Create 버튼을 클릭한다.
- 로그아웃을 진행하고 방금 생성한 테스트 계정으로 로그인을 진행한다.
- 테스트 계정으로 로그인 시 권한이 없기 때문에, 빨간 영역의 항목들이 disable된 것을 확인할 수 있다.
- Admin 계정으로 로그인 한 후, Administration -> Security -> Global Permissions에서 계정에 대한 권한을 설정할 수 있다.
SonarQube의 Rules에서 프로젝트 언어에 맞게 검사하는 Bug, Code Smell 등을 확인할 수 있다.
5. Project build.gradle 수정
buildscript {
ext {
springBootVersion = '1.5.4.RELEASE'
jacocoVersion = '0.8.7' // Jacoco version 명시
}
repositories {
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1" // Sonarqube Dependency 설정
}
}
plugins {
id 'org.springframework.boot' version '2.5.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'com.google.cloud.tools.jib' version '3.1.4'
}
apply plugin: 'org.sonarqube' // plugin 적용
apply plugin: 'jacoco' // plugin 적용
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
jacoco{
toolVersion = "${jacocoVersion}"
}
jacocoTestReport { // Jacoco 분석 결과를 어떤 파일 형태로 작성할 것인가
reports{
html.enabled=true
xml.enabled=true
csv.enabled=true
}
}
tasks.withType(JavaCompile) { // 한글, 영어 이외의 문자를 인코딩
options.encoding = 'UTF-8'
}
sonarqube {
properties {
property "sonar.projectName","<Project Name>"
property "sonar.exclusions", "**/generated-*/**/*"
property "sonar.projectKey", "org.sonarqubeJacocoCodeCoverage"
property "sonar.reportPath" , "${project.buildDir}/jacoco/test.exec"
property "sonar.host.url", "http://<SonarQube Private IP>:9000"
property "sonar.sources", "src/main/java"
property "sonar.tests", "src/test/java"
property "sonar.login", "<SonarQube ID>"
property "sonar.password", "<SonarQube PW>"
}
}
tasks['sonarqube'].dependsOn test
jib { // docker Image build
from {
image = 'adoptopenjdk/openjdk11:alpine-jre'
}
to {
image = '<AWS ECR URL>/<Image Repository Name>'
tags = ['<Image Tag Name>']
}
container {
entrypoint = ['java', '-Dspring.profiles.active=test', '-jar', 'spring-boot-gradle-demo-0.0.1-SNAPSHOT.jar']
// mainClass = 'com.test.StartApplication'
jvmFlags = ['-Xms512m', '-Xmx512m', '-Xdebug', '-XshowSettings:vm', '-XX:+UnlockExperimentalVMOptions', '-XX:+UseContainerSupport']
ports = ['8080']
environment = [SPRING_OUTPUT_ANSI_ENABLED: "ALWAYS"]
labels = [version:project.version, name:project.name, group:project.group]
creationTime = 'USE_CURRENT_TIMESTAMP'
format = 'Docker'
}
extraDirectories {
paths {
path {
from = file('build/libs')
}
}
}
}
* 실행 명령어
- 예제 코드 빌드 명령어
- ./gradlew clean build --info
- ./gradlew clean build --info
- Jacoco 코드 커버리지 측정 및 리포트 작성 명령어
- ./gradlew jacocoTestCoverageVerification --info
- ./gradlew jacocoTestReport --info
- SonarQube 코드 품질 스캔 결과 연동 명령어
- ./gradlew sonarqube --info
- ./gradlew sonarqube --info
- Docker 이미지 빌드 및 Push 명령어
- ./gradlew jib --console=plain
- ./gradlew jib --console=plain
'정리 > 유용 기능' 카테고리의 다른 글
Multi Module (0) | 2022.11.13 |
---|---|
Android Studio 없이 Emulator 실행하기 (0) | 2022.10.20 |
유용한 도구 모음 (1) (0) | 2022.10.06 |
[IntelliJ] 클래스 생성 시 자동 주석 설정 (0) | 2022.09.06 |