프로젝트/개인 프로젝트(2023.11.13-2023.12.18)

[개인프로젝트] 코드 커버리지??

dal_been 2024. 2. 22. 13:22
728x90

개인프로젝트때 왠만하면 진짜 꼼꼼하게 테스트 코드를 작성했다.
물론 초반에는 왜 테스트코드를 작성해야되지..? 에 대한 의문이 있었지만.. 작성하면서 느낀점은
1. 작성한 코드가 의도한 대로 작동하는지 검증할 수 있다.
-> 테스트코드를 통해서 동작하는 방식과 결과가 내가 작성한 대로 나오는지 활인할 수 있다.
2. 코드를 수정할때 변경에 대한 영향도를 쉽게 파악할 수 있다.
-> 아무래도 후반에 리팩토링후 테스트코드 돌릴때 에러가 나올때가 있었다. 근데 만약 내가 테스트코드 안짜놓고 어플리케이션을 돌렸다면어렵게 어디서 에러가 나오는지 찾을 수없을거같다. 즉 테스트코드 덕분에 수정으로 인한 영향력을 빠르게 파악할 수 있었다.
 
나의 경우 유닛 테스트코드를 많이 짰다. 개별코드 단위가 내가 의도한대로 작동하는지 확인하였다.
근데 궁금했다.. 과연 내가 잘 테스트코드를 만들고 있는 걸까,,,,? 그래서 찾아본게 코드 커버리지다.!
 


코드 커버리지?

 
코드 커버리지란 테스트코드가 프로덕션 코드를 얼마나 실행했느지 백분율로 나타내는 지표이다.
즉 테스트코드가 실제로 프로덕션 코드를 얼마나 몇 퍼센트 검증하고 있는지를 나타낸다.
 
코드 커버리지 측정 기준에는 여러가지가 존재한다.
 
1. 함수 커버리지
어떤 함수가 최소 1번이상 호출되었는지를 기준으로 커버리지를 계산한다. 함수 내부의 모든 코드가 실행되었는지는 판단 기준에서 제외한다.

void test1(){}

void test2(){}

void test3(){}

void test4(){}

위와 같은 4개의 함수가 있고, 테스트코드가 만약 test2,test3만 실행한다면 4개중 2개만 실행되거니까 테스트코드 커버리즈는50%가 된다.
즉 함수 커버리지 = (실행된 함수의 수 / 전체 함수의 수) * 100
 
2. 구문 커버리지
라인 커버리지 라고 부르기도 한다. 프로덕션 코드의 전체 구문에서 몇줄의 구문이 실행되었는지를 기준으로 판단한다.

void test(int k) {

	System.out.println("a"); //1
    if(k>10){ //2
    	System.out.println("b"); //3
    }
    System.out.println("c"); //4
}

위 코드를 테스트한다고 했을 때 k =12 라고 한다면 3번코드는 실행되지 못한다.
총 4개의 라인에서 1,2,4번의 라인만 실행되므로 구문커버리지는 3/4*100 = 75%가 된다.
즉 구문 커버리지 = (실행된 구문의  수 / 전체 구문의수 )*100
 
3. 결정 커버리지 
브랜치 커버리지라고 부르기도 한다. 프로덕션 코드에 조건문이 있는경우, 조건문의 전체 조건식이 true/false 케이스를 최소한 한번 실행되면 충족된다.

void test(int x, int y){

	System.out.println("start"): //1
    if(x>0 && y>0 ){  //2
    	System.out.println("line"); //3
    }
    
    System.out.println("end"); //4
}

 
위 테스트코드에 x=1,y=1과 x=-1,y=-1대입한다고 가정해보자.
첫번째 데이터의 경우 true이기때문에 3번코드를 실행한다.
두번째 데이터의 경우 flase이기 때문에 4번코드를 실행한다.
그럼 두 데이터를 사용하여 전체 조건식에서 true와 false 모두 반환했으므로 결정 커버리지를 충족한다.
 
4. 조건 커버리지
결정커버리지와 다르게 전체 조건식이 아니라 개별 조건식을 기준으로 판단한다. 

if(x>0&&y<0){

}

 
위의 테스트코드에 x=1,y=1과 x=-1,y=-1대입한다고 가정해보자.
x>0에서는 1과 -1을 넣어 봄으로써 true/false를 만족한다.
y>0에서도 1과 -1을 넣어봄으로써 true/false를 만족한다.
이렇게 각가 개별조건식?에 대해서 true/false를 모두 만족했을때 조건커버리지를 충족한다고 할 수 있다.
 
5. 조건/결정 커버리지
조건커버리지, 결정 커버리지 모두 충족되는 조건이다. 개별조건, 전체 조건 모두 한번씩 true/false가 선택되어야한다.
 
 
근데 search해보니 구문커버리지가 가장 대표적으로 많이 사용된다고 한다.
그 이유는 조건 커버리지나 브랜치 커버리지의 경우 코드 실행에 대한 테스트보다느 로직 시나리오에 대한 테스트에 더 가깝다고 볼 수 있기 대문이다. 예를 들어 데이터가 조건문에 대해서 true/false에 대해 모두 만족할때 코드커버리지가 만족되었다 라고 한다.
그리고 조건 커버리지나 브랜치 커버리지의 경우 조건문이 코드에 없다면 아예 테스트 대상에서 제외된다.
 
그렇기 때문에 라인 커버리지를 많이 사용하는 것같다(조건문이 없으면 조건, 브랜치 커버리지는 테스트 대상에서 제외하기 때문)
따라서 라인 커버리지의 경우 만족했을 경우 테스트코드 실행에 문제가 없다는 것을 보장할 수 있다. (물론 조건에 대한 모든 true/false시나리오에 대해서 테스트했다고 보장할 수 없지만)
 


내 프로젝트에는 이렇게 해놨다.

limit {
		counter = 'LINE'
		value = 'COVEREDRATIO'
		minimum = 0.75

}

limit {
		counter = 'BRANCH'
		value = 'COVEREDRATIO'
		minimum = 0.75

}

 
라인 커버리지를 통해 실행에는 문제가 없는지 살펴보고, 조건문에 대한 테스트로 브랜치 커버리지를 사용하여 75%이상 만족할시 build가 되게 하였다. 결과적으로..
 

다행히 잘 만족하였다..