테스트에 대하여 알아보다 생긴 궁금증..
각종 테스트 기법, 테스트 종류들에 대해 알아보고 예제들을 보다가 계속 가시지 않는 궁금증이 하나 생겼다.
"그런데 이거, 효율적이긴 한거야? 보다보니까 굉장히 이상한데?"

비 효율적이라고 생각되는 부분이 한두가지가 아니었다.
- 코드 작성자가 테스트 케이스를 만들면, 아무리 범용적으로 생각하더라도 본인이 작성자 이기 때문에 통과 용도로 밖에 테스트 케이스를 짜지 못할 확률이 높다.
- 무조건 테스트 케이스를 먼저 만들고 개발에 들어간다면, 너무 비효율적이다.
- 테스트 케이스가 많아질수록 개발에 방해가 될 요소가 너무 많다. (인력은 한정되어 있고, 기간도 마찬가지. 테스트 케이스에 대한 cost가 점점 늘어만 가는데 이부분을 해결하느라 실제 개발에 소비되는 cost가 줄어들 수 있다.)
일단 의문점에 대해서 하나하나 살펴보자.
코드 작성자가 테스트 케이스를 만들 경우
첫번째로, 코드 작성자가 직접 테스트 케이스를 만들경우, 실제 개발에서도 그렇지만 개발자는 본인이 의도한 대로 테스트를 진행하는 경우가 많다.
즉, 테스트 케이스 자체를 통과용으로 만들 가능성이 농후하기 때문에 실질적인 테스트의 의미가 퇴색할 가능성이 높다.

물론 테스트 케이스를 직접 작성하더라도 의도한 대로 흘러가지 않을 경우가 대다수이긴 할 것이다. 해당 부분에 대해서 코드를 직접 수정하고, 어느 부분이 틀렸는지 쉽게 알아 챌 수 도 있을 것이다.
그런데 이건 그냥 실제 개발환경에서 돌려도 마찬가지인데, 개발 단계가 초기단계라고 생각한다면 그냥 개발환경 위에서 컴파일 하면서 테스트 해도 크게 문제가 되지는 않을 것이다.
이에 따른 해결 방법으로 생각해 본게, 테스트 데이터들을 DB에 넣고 테스트 코드를 돌릴 때 해당 값들을 불러와서 테스트 하는 방법이었다. 이렇게 하면 함수를 직접 개발한 사람이 아니라도 테스트 케이스에 직접 데이터를 넣어보면서 테스트를 진행 할 수 있기 때문에 좀 다방면으로 테스트를 진행 할 수 있어, (물론 데이터를 넣는 사람에게 해당 함수가 무엇인지 설명을 해야 겠지만) 정확도를 높힐 수 있다.
그런데 위와 같은 경우에도, 테스트 데이터를 넣어야 하는 인프라를 구축해야하고 소통을 하는데 있어서 Cost가 소비된다.
테스트 커버리지 (테스트를 수행한 범위) 는 넓어지고 테스트 코드 작성에 드는 Cost는 줄어들었지만 테스트 데이터의 생성 Cost가 들어가기 때문에 비용적인 측면에서는 크게 다를 바는 없다.
무조건 테스트 케이스를 먼저 만들고, 이후에 개발에 들어간다고?
이건 아무리 생각해도 비용대비 리턴이 너무 적다.
너무 뻔한 함수들의 경우에는 테스트 케이스를 만들 필요도 없을 것이고.. 유지보수 측면에서도 테스트 케이스만 건드리느라 아예 개발 진도가 못나갈 가능성이 농후하다.

배보다 배꼽이 커지는 경우.
개인적으로는 완전 배제 되어야지만 하는 케이스로 생각된다.
테스트 케이스가 많아질수록 개발에 방해가 될 요소가 너무 많다.
위에서와 같은 말인데, 테스트케이스를 관리하느라 궁극적으로는 개발에 방해가 될 요소가 너무 많다.
너무 많은 테스트 케이스는 결국 어플리케이션이 산으로 갈 가능성이 높아만 진다.
즉, 테스트 케이스를 만드는데 있어서는 어떤 테스트 케이스를 만들고 관리해야 진짜 효율적으로, 테스트를 테스트답게 진행 할 수 있을지가 관건인 것 같다.
이게 내 생각만 그런 걸까? 구글 서칭을 해보면 대부분 테스트 케이스에 대한 예찬이 많다..
그래서 좀 더 찾아보았다.
E2E 테스트는 그만. 테스트 개선기
프로덕트를 안정적으로 운영하기 위해서는 테스트 방법을 잘 설계하는 것이 필수이다. 사내에는 Browser Stack을 활용한 E2E 테스트가 존재하였고 master 브랜치의 CD Flow에 해당 테스트가 포함되어 있
velog.io
비단, 내 생각만은 아닌 것 같았다.
그러면, 효율적인 테스트 케이스란 뭘까?
개인적으로 생각하는 효율적인 테스트 케이스
굉장히 주관적인, 개인적으로 생각하는 효율적인 테스트 케이스이다.
개발 단계에 따라서도 많이 나뉘게 될 것 같다.
- 개발 초기 단계에서는(또는 어플리케이션 자체가 간단한 경우), 굳이 테스트 케이스를 만들 필요가 없다.
- 이미 개발된 파트에서, 개발된 함수를 수정 할 때 사이드 이펙트에 대한 테스트 케이스를 관리하는 경우.
- 입력값에 대한 결과값이 명확한데, 로직이 복잡한 경우 또는 개발단계에서 직접 테스트하기가 어려운 경우
- 라이브중인 서비스에 대하여, 예상치 못한 값이 들어와 버그가 발생했을 경우
일단 이외에도 있을 법 한데, 실질적으로 제대로 된 테스트를 접해본게 오늘이라서 이정도가 생각이 난다.
1. 개발 초기 단계에서는(또는 어플리케이션 자체가 간단한 경우), 굳이 테스트 케이스를 만들 필요가 없다.
물론, 예외는 있다. 3번에서 얘기 할 부분이라 잠시 넘어가고, 초기단계이거나 어플리케이션 자체가 간단한 경우 테스트케이스를 만들고 그걸 유지보수할 필요가 없다.
그 시간에 로직 더 짜고, 즉각적으로 테스트가 가능한 것들은 즉각적으로 테스트하는게 여러모로 비용 절감이 된다.
2. 이미 개발된 파트에서, 사이드 이펙트에 대한 테스트 케이스를 관리하는 경우
이 때가 정말 테스트 케이스를 관리하는데 효율적인 케이스 인 것 같다.
일단, 어떤 방식으로 테스트를 작성하고, 어떤 사이드 이펙트가 생겼는지에 대한 로그를 남김에도 유효할 것이다.
현재 상태에 따라서 먼저 테스트 케이스를 작성하고,
변경된 함수에서 테스트를 실행했을 때 테스트 결과가 실패가 나오게 된다면 어딘가 사이드 이펙트가 있다 라는 것이기 때문..! 그렇게 되면 사이드이펙트가 발생한 부분에 대하여 예측도 쉬워지고 어느파트를 고쳐야 하는지도 쉽게 파악이 될 것이다.
3. 입력값에 대한 결과값이 명확한데, 로직이 복잡한 경우 또는 실 개발단계에서 직접 테스트 하기가 어려운 경우
이런 경우가 첫번째, 굳이 테스트 케이스를 만들 필요가 없다에 대한 예외가 될 것 같다.
간단한 예제라.. 로직이 복잡하진 않은데 일단 결과값이 명확한 경우에 대한 예를 잠깐 들어보자면,
(현재 진행중인 개인 프로젝트에는 아쉽게도 로직이 엄청 복잡한 경우가 없다 ㅠㅠ..)
typescriptexport const getCombinations = <T>(targetArr: T[]) => {
let result: T[][] = []
let f = (tempArr: T[], targetArr: T[]) => {
for(let i = 0; i < targetArr.length; i++) {
result = [...result, [...tempArr, targetArr[i]]]
f([...tempArr, targetArr[i]], targetArr.slice(i+1))
}
}
f([],targetArr)
return result
}
위와 같은 Combination 함수를 만들었다면 이게 정상적으로 Combination 역할을 하는지, 입력값에 따른 결과값이 명확한 경우에는 테스트케이스를 만들어두고 테스트가 통과하지 못한다면 어딘가 버그가 있다라는 것을 알게 될 것이다.
실 개발단계에서 직접 테스트 하기 어려운 경우에도, 해당 함수를 호출하려면 여러 백데이터가 미리 존재해야 하고 그 백데이터들을 위해서 여러 동작들이 필요할 경우가 있을 텐데, (제가 가장 많이 겪은 경우.. 대표적으로 fabric.js를 이용하여 웹 이미지 에디터를 만드는데, 수학적으로 굉장히 많은 연산이 필요한 부분이 있었습니다.)
실제로 로직에 대해 테스트를 진행하려면 앞서서 행동해야 하는 행위가 많았다. (함수에 데이터를 넣어주기 까지의 전 행위)
이럴때, Mock을 이용하여서 테스트 케이스를 만들고 검증한다면? 개발이 한참 수월해 질 것이다.

4. 라이브중인 서비스에 대하여, 예상치 못한 값이 들어와 버그가 발생했을 경우
예상치 못한 값들은 결국 개발자가 생각하지 못한 값들이다. 그래서 버그가 발생했을 것이고, 아마 일반적으로 예상치 못한 값이 들어와서 버그가 발생하게 된다면 테스트 커버리지에 대해 좀 더 명확하고 넓게 개발자가 생각할 수 있을 것이다.
또한 테스트 케이스로 돌리기 때문에, 이미 라이브중인 서비스 (dev 모드로 한다고 하더라도,) 를 구동하고 그 위에서 테스트 하는 것 보다 안정적이고 빠르게 코드를 수정 할 수 있을거다.
추가, 그래서 결론.
결국엔 테스트에 들어가는 비용만큼, 개발쪽에서 비용이 줄어야 하는 교차점을 찾아야 하고 해당 경우에 대하여 테스트 케이스를 만들고 관리하는 것이 개인적인 결론이다.
테스트를 함으로서 개발이 쉬워지는 포인트!
분명히 DevOps의 목표가 더 빠르고, 안정적으로 서비스를 제공하는게 목표인데 이 의미가 퇴색되면 안될 것 같다.
이 글을 다 읽어주시는 분이 있을지 모르겠지만..
다른 의견이나, 추가적으로 어떨 때 테스트케이스를 만들고 관리하는게 진짜 효율적으로 개발에 도움을 줄지에 대하여 아시는 분들은 알려주시면 정말정말 압도적 감사..
'DevOps' 카테고리의 다른 글
[Postman] 쉽게 API 명세서 만들기 (0) | 2023.06.02 |
---|---|
테스트에 관하여.. (1) | 2023.05.08 |
TypeScript에 jest를 적용해보자 (0) | 2023.05.08 |
[Ansible] Ansible + git Action + EC2 자동배포 + IAM 보안 설정 (0) | 2023.04.27 |
[gitAction] Ansible + gitAction을 이용한 EC2 자동배포 (0) | 2023.04.26 |
테스트에 대하여 알아보다 생긴 궁금증..
각종 테스트 기법, 테스트 종류들에 대해 알아보고 예제들을 보다가 계속 가시지 않는 궁금증이 하나 생겼다.
"그런데 이거, 효율적이긴 한거야? 보다보니까 굉장히 이상한데?"

비 효율적이라고 생각되는 부분이 한두가지가 아니었다.
- 코드 작성자가 테스트 케이스를 만들면, 아무리 범용적으로 생각하더라도 본인이 작성자 이기 때문에 통과 용도로 밖에 테스트 케이스를 짜지 못할 확률이 높다.
- 무조건 테스트 케이스를 먼저 만들고 개발에 들어간다면, 너무 비효율적이다.
- 테스트 케이스가 많아질수록 개발에 방해가 될 요소가 너무 많다. (인력은 한정되어 있고, 기간도 마찬가지. 테스트 케이스에 대한 cost가 점점 늘어만 가는데 이부분을 해결하느라 실제 개발에 소비되는 cost가 줄어들 수 있다.)
일단 의문점에 대해서 하나하나 살펴보자.
코드 작성자가 테스트 케이스를 만들 경우
첫번째로, 코드 작성자가 직접 테스트 케이스를 만들경우, 실제 개발에서도 그렇지만 개발자는 본인이 의도한 대로 테스트를 진행하는 경우가 많다.
즉, 테스트 케이스 자체를 통과용으로 만들 가능성이 농후하기 때문에 실질적인 테스트의 의미가 퇴색할 가능성이 높다.

물론 테스트 케이스를 직접 작성하더라도 의도한 대로 흘러가지 않을 경우가 대다수이긴 할 것이다. 해당 부분에 대해서 코드를 직접 수정하고, 어느 부분이 틀렸는지 쉽게 알아 챌 수 도 있을 것이다.
그런데 이건 그냥 실제 개발환경에서 돌려도 마찬가지인데, 개발 단계가 초기단계라고 생각한다면 그냥 개발환경 위에서 컴파일 하면서 테스트 해도 크게 문제가 되지는 않을 것이다.
이에 따른 해결 방법으로 생각해 본게, 테스트 데이터들을 DB에 넣고 테스트 코드를 돌릴 때 해당 값들을 불러와서 테스트 하는 방법이었다. 이렇게 하면 함수를 직접 개발한 사람이 아니라도 테스트 케이스에 직접 데이터를 넣어보면서 테스트를 진행 할 수 있기 때문에 좀 다방면으로 테스트를 진행 할 수 있어, (물론 데이터를 넣는 사람에게 해당 함수가 무엇인지 설명을 해야 겠지만) 정확도를 높힐 수 있다.
그런데 위와 같은 경우에도, 테스트 데이터를 넣어야 하는 인프라를 구축해야하고 소통을 하는데 있어서 Cost가 소비된다.
테스트 커버리지 (테스트를 수행한 범위) 는 넓어지고 테스트 코드 작성에 드는 Cost는 줄어들었지만 테스트 데이터의 생성 Cost가 들어가기 때문에 비용적인 측면에서는 크게 다를 바는 없다.
무조건 테스트 케이스를 먼저 만들고, 이후에 개발에 들어간다고?
이건 아무리 생각해도 비용대비 리턴이 너무 적다.
너무 뻔한 함수들의 경우에는 테스트 케이스를 만들 필요도 없을 것이고.. 유지보수 측면에서도 테스트 케이스만 건드리느라 아예 개발 진도가 못나갈 가능성이 농후하다.

배보다 배꼽이 커지는 경우.
개인적으로는 완전 배제 되어야지만 하는 케이스로 생각된다.
테스트 케이스가 많아질수록 개발에 방해가 될 요소가 너무 많다.
위에서와 같은 말인데, 테스트케이스를 관리하느라 궁극적으로는 개발에 방해가 될 요소가 너무 많다.
너무 많은 테스트 케이스는 결국 어플리케이션이 산으로 갈 가능성이 높아만 진다.
즉, 테스트 케이스를 만드는데 있어서는 어떤 테스트 케이스를 만들고 관리해야 진짜 효율적으로, 테스트를 테스트답게 진행 할 수 있을지가 관건인 것 같다.
이게 내 생각만 그런 걸까? 구글 서칭을 해보면 대부분 테스트 케이스에 대한 예찬이 많다..
그래서 좀 더 찾아보았다.
E2E 테스트는 그만. 테스트 개선기
프로덕트를 안정적으로 운영하기 위해서는 테스트 방법을 잘 설계하는 것이 필수이다. 사내에는 Browser Stack을 활용한 E2E 테스트가 존재하였고 master 브랜치의 CD Flow에 해당 테스트가 포함되어 있
velog.io
비단, 내 생각만은 아닌 것 같았다.
그러면, 효율적인 테스트 케이스란 뭘까?
개인적으로 생각하는 효율적인 테스트 케이스
굉장히 주관적인, 개인적으로 생각하는 효율적인 테스트 케이스이다.
개발 단계에 따라서도 많이 나뉘게 될 것 같다.
- 개발 초기 단계에서는(또는 어플리케이션 자체가 간단한 경우), 굳이 테스트 케이스를 만들 필요가 없다.
- 이미 개발된 파트에서, 개발된 함수를 수정 할 때 사이드 이펙트에 대한 테스트 케이스를 관리하는 경우.
- 입력값에 대한 결과값이 명확한데, 로직이 복잡한 경우 또는 개발단계에서 직접 테스트하기가 어려운 경우
- 라이브중인 서비스에 대하여, 예상치 못한 값이 들어와 버그가 발생했을 경우
일단 이외에도 있을 법 한데, 실질적으로 제대로 된 테스트를 접해본게 오늘이라서 이정도가 생각이 난다.
1. 개발 초기 단계에서는(또는 어플리케이션 자체가 간단한 경우), 굳이 테스트 케이스를 만들 필요가 없다.
물론, 예외는 있다. 3번에서 얘기 할 부분이라 잠시 넘어가고, 초기단계이거나 어플리케이션 자체가 간단한 경우 테스트케이스를 만들고 그걸 유지보수할 필요가 없다.
그 시간에 로직 더 짜고, 즉각적으로 테스트가 가능한 것들은 즉각적으로 테스트하는게 여러모로 비용 절감이 된다.
2. 이미 개발된 파트에서, 사이드 이펙트에 대한 테스트 케이스를 관리하는 경우
이 때가 정말 테스트 케이스를 관리하는데 효율적인 케이스 인 것 같다.
일단, 어떤 방식으로 테스트를 작성하고, 어떤 사이드 이펙트가 생겼는지에 대한 로그를 남김에도 유효할 것이다.
현재 상태에 따라서 먼저 테스트 케이스를 작성하고,
변경된 함수에서 테스트를 실행했을 때 테스트 결과가 실패가 나오게 된다면 어딘가 사이드 이펙트가 있다 라는 것이기 때문..! 그렇게 되면 사이드이펙트가 발생한 부분에 대하여 예측도 쉬워지고 어느파트를 고쳐야 하는지도 쉽게 파악이 될 것이다.
3. 입력값에 대한 결과값이 명확한데, 로직이 복잡한 경우 또는 실 개발단계에서 직접 테스트 하기가 어려운 경우
이런 경우가 첫번째, 굳이 테스트 케이스를 만들 필요가 없다에 대한 예외가 될 것 같다.
간단한 예제라.. 로직이 복잡하진 않은데 일단 결과값이 명확한 경우에 대한 예를 잠깐 들어보자면,
(현재 진행중인 개인 프로젝트에는 아쉽게도 로직이 엄청 복잡한 경우가 없다 ㅠㅠ..)
typescriptexport const getCombinations = <T>(targetArr: T[]) => {
let result: T[][] = []
let f = (tempArr: T[], targetArr: T[]) => {
for(let i = 0; i < targetArr.length; i++) {
result = [...result, [...tempArr, targetArr[i]]]
f([...tempArr, targetArr[i]], targetArr.slice(i+1))
}
}
f([],targetArr)
return result
}
위와 같은 Combination 함수를 만들었다면 이게 정상적으로 Combination 역할을 하는지, 입력값에 따른 결과값이 명확한 경우에는 테스트케이스를 만들어두고 테스트가 통과하지 못한다면 어딘가 버그가 있다라는 것을 알게 될 것이다.
실 개발단계에서 직접 테스트 하기 어려운 경우에도, 해당 함수를 호출하려면 여러 백데이터가 미리 존재해야 하고 그 백데이터들을 위해서 여러 동작들이 필요할 경우가 있을 텐데, (제가 가장 많이 겪은 경우.. 대표적으로 fabric.js를 이용하여 웹 이미지 에디터를 만드는데, 수학적으로 굉장히 많은 연산이 필요한 부분이 있었습니다.)
실제로 로직에 대해 테스트를 진행하려면 앞서서 행동해야 하는 행위가 많았다. (함수에 데이터를 넣어주기 까지의 전 행위)
이럴때, Mock을 이용하여서 테스트 케이스를 만들고 검증한다면? 개발이 한참 수월해 질 것이다.

4. 라이브중인 서비스에 대하여, 예상치 못한 값이 들어와 버그가 발생했을 경우
예상치 못한 값들은 결국 개발자가 생각하지 못한 값들이다. 그래서 버그가 발생했을 것이고, 아마 일반적으로 예상치 못한 값이 들어와서 버그가 발생하게 된다면 테스트 커버리지에 대해 좀 더 명확하고 넓게 개발자가 생각할 수 있을 것이다.
또한 테스트 케이스로 돌리기 때문에, 이미 라이브중인 서비스 (dev 모드로 한다고 하더라도,) 를 구동하고 그 위에서 테스트 하는 것 보다 안정적이고 빠르게 코드를 수정 할 수 있을거다.
추가, 그래서 결론.
결국엔 테스트에 들어가는 비용만큼, 개발쪽에서 비용이 줄어야 하는 교차점을 찾아야 하고 해당 경우에 대하여 테스트 케이스를 만들고 관리하는 것이 개인적인 결론이다.
테스트를 함으로서 개발이 쉬워지는 포인트!
분명히 DevOps의 목표가 더 빠르고, 안정적으로 서비스를 제공하는게 목표인데 이 의미가 퇴색되면 안될 것 같다.
이 글을 다 읽어주시는 분이 있을지 모르겠지만..
다른 의견이나, 추가적으로 어떨 때 테스트케이스를 만들고 관리하는게 진짜 효율적으로 개발에 도움을 줄지에 대하여 아시는 분들은 알려주시면 정말정말 압도적 감사..
'DevOps' 카테고리의 다른 글
[Postman] 쉽게 API 명세서 만들기 (0) | 2023.06.02 |
---|---|
테스트에 관하여.. (1) | 2023.05.08 |
TypeScript에 jest를 적용해보자 (0) | 2023.05.08 |
[Ansible] Ansible + git Action + EC2 자동배포 + IAM 보안 설정 (0) | 2023.04.27 |
[gitAction] Ansible + gitAction을 이용한 EC2 자동배포 (0) | 2023.04.26 |