Non functional testing이란?
비기능 테스트(Non functional testing)는 기능 테스트(functioanl testing)과 마찬가지로 software가 제대로 작동하는지 testing하는 것입니다. 다만, functional testing은 software의 동작을 검증하는 것이고 이러한 functional testing이 다루지 않는 부분을 검증하는 것이 non functional testing입니다.
Non functional testing의 중요성
두 가지 testing 모두 입력 값에 따른 출력 값을 확인하는 형태의 “블랙박스 테스트” 입니다. 다만, 두 testing은 테스트의 결과를 판단하는 방식이 다릅니다.
functional testing의 경우 테스트의 결과가 “올바르다”, “올바르지 않다” 와 같이 2가지로 보통 나타납니다.
하지만, non functional testing의 경우 그렇지 않습니다. non finctional testing은 functional testing 처럼 테스트의 결과를 YES/NO로 판단하기 힘든 부분에 대해서 testing을 진행하는 것입니다.
예를 들어, 결제 기능에 대해서 testing을 진행한다고 해봅시다.
functional testing을 진행한다면, 결제가 정상적으로 작동하는 지를 판단하여 “작동 한다”와 “작동하지 않는다”로 결론을 내릴 것입니다.
성공적으로 작동한다면 우리는 해당 기능이 정상이라고 판단할 것입니다.
하지만, 만약 결제 기능이 완료되기 까지 60초가량의 응답 시간이 걸린다고 한다면, 과연 이것이 정상인지 의문이 들 것입니다.
응답 시간에 대해 기준을 정해두고 만약 해당 기준을 넘어간다면, 에러 로그를 남기고 이를 모니터링 하여 어떤 기능이 어떤 상황에서 비정상적인 동작을 보였는 지를 찾아야 합니다.
즉, 기능의 정상 작동 여부도 중요하지만 위와 같이 “비기능”적인 측면에서도 다방면의 testing을 진행함으로써 서비스의 품질을 유지하고 높일 수 있습니다.
non functional testing의 종류는 매우 다양하지만, 통상적으로 다음 7가지의 유형으로 나눌 수 있습니다.
7가지 타입의 Non functional testing
- Performance Tests
- Load Tests
- Stress Tests
- Volume Tests
- Security Tests
- Upgrade & Installation Tests
- Recovery Tests
1. Performance Tests
software의 component들이 얼마나 잘 동작하는 지를 확인하는 test입니다. perfomance test를 통해서 해당 software의 디자인 혹은 아키텍쳐에서의 issue를 찾을 수 있습니다.
주로, 다음의 요소를 통해 판단을 내립니다.
- 응답 시간 측정
- 병목 구간 식별
- 실패 지점 찾기
이러한 performance test를 통해서 해당 software의 품질을 보장할 수 있습니다.
2. Load Tests
Load test는 소프트웨어가 “정상적인 조건”에서 어떻게 동작하는지 확인하는 테스트 입니다. 이러한 테스트를 통해서 소프트웨어가 처리할 수 있는 작업량을 미리 결정할 수 있습니다.
여러 프로그램을 동시에 실행하거나, 서버에 많은 트래픽이 발생하거나, 많은 양의 파일을 다운로드하여 Load Test를 수행할 수 있습니다.
3. Stress Tests
Stress Test는 소프트웨어가 “비정상적인 조건”에서 어떻게 동작하는지 확인하는 테스트 입니다. 이러한 테스트를 통해서 어느 지점에서 해당 소프트웨어를 중단되는 지, 그 한계를 측정할 수 있습니다.
또한 이러한 Stress를 받았을 때 시스템이 올바르게 작동하는 지도 확인하는 작업입니다. 예를 들어 올바른 에러 메시지를 띄우는지, 시스템이 완전히 종료되는지, 혹은 어떻게 다시 회복하는 지 등등 시스템의 대처를 테스트하는 과정입니다.
4. Volume Tests
Volume test는 대용량의 데이터가 데이터베이스에 삽입, 전달될 때 해당 시스템의 performance에 어떤 영향을 미치는 지 확인하는 테스트입니다.
이러한 테스트를 통해서 데이터의 volume이 증가할 때의 문제점을 파악할 수 있습니다. 이러한 테스트를 “flood testing”이라고도 합니다.
또한 volume test를 사용하여 데이터 손실, 경고 또는 오류 메시지 또는 데이터 스토리지 문제가 있는지 확인할 수 있고, 시스템이 특정 데이터 볼륨에 대해 예상대로 반응하는지 확인할 수 있습니다.
5. Security Tests
Security Test를 통해서 데이터를 손상시킬 수 있는 결함들을 찾아냅니다.
다음과 같은 작업을 통해 해당 test를 진행합니다.
- 취약성 검사
- 침투 테스트
- 리스크 평가
이 외에도 다양한 검사를 통해서 해당 시스템의 안전을 확인할 수 있습니다.
6. Upgrade and Installation Tests
Upgrade and Installation Test는 소프트웨어가 모든 사용자의 컴퓨터에서 제대로 작동하는지 확인하는 테스트입니다.
기존 사용자의 경우 Upgrade test를, 신규 사용자의 경우 Installation test를 수행합니다.
7. Recovery Tests
Recovery Test는 시스템 상 충돌이나 오류에 대해서 해당 소프트웨어가 얼마나 빨리 복구하는 지를 테스트하는 것입니다.
이러한 테스트는 의도적으로 해당 시스템을 고장나게 함으로써 수행됩니다.
staging 서버
해당 글에서 진행하는 실습은 단순히 로컬 환경에서 서버를 띄우고 부하 테스트를 진행하지만, 실제로 서비스를 배포하는 서버에서 부하 테스트를 무리하게 진행하다가 서버가 중지되는 참사가 발생할 수 있습니다.
따라서 실제 배포 서버에 테스트를 진행하는 것이 아니라 배포 서버와 동일한 사양의 또 다른 서버, staging 서버를 만들고 그 서버에 부하 테스트를 진행하는 것이 바람직합니다!
Stress test 실습 - Artillery
로컬 환경에서 서버를 띄운 후, 의도적으로 많은 양의 요청을 발생 시켜서 직접 부하 테스트를 실시해보도록 하겠습니다.
아마도 node.js로 서버를 띄운다면 일정량의 요청은 비동기적으로 처리할 수 있겠지만, 어느 정도 요청량이 많아지면 서버의 메모리 용량을 초과하면서 서버가 다운될 것입니다.
부하 테스트 tool
- 자바 환경 : jmeter, ngrinder, grinder
- node 환경 : ****artillery
직접 제작했던 서버 어플리케이션의 성능을 테스트해 볼 수 있는 의미 있는 시간이 될 것입니다.
Artillery의 특징
- HTTP(S), Socket.io, Websocket 등 다양한 프로토콜을 지원합니다.
- 시나리오 테스트 작성이 가능합니다.
- 풍부한 CLI 커맨드를 제공합니다.
- 리포트 페이지를 따로 제공합니다.
artillery의 공식 문서를 보며 실습을 진행해 봅시다.
Installing Artillery
stable release 설치는 다음과 같은 npm 커맨드를 입력한다.
npm install -g artillery@latest
+) docker container의 경우
RUN npm install -g artillery
+) 설치 확인
artillery dino
설치가 정상적으로 완료되었다면, 다음과 같은 공룡 그림이 뜹니다!
package.json 변경을 확인한 후, 미리 준비했던 서버를 실행시켜줍니다.
제가 사용한 프로젝트는 다음과 같습니다.
필요하신 분들은 git clone 하셔서 사용하셔도 됩니다! 다만, db 연결과 구성은 각자 하셔야 합니다. ERD 이미지가 있으니 따라서 구성하시면 됩니다.
https://github.com/great-park/Node.js_Module_Pattern
소스파일 경로로 터미널을 열고, node index.js 를 입력해서 서버를 실행하시면 됩니다!
Test script 작성
다음과 같이 파일을 작성하여 테스트할 환경을 설정할 수 있습니다.
이 파일은 json 형식으로 작성해도 괜찮습니다!
config:
target: "https://example.com/api"
phases:
- duration: 60
arrivalRate: 5
name: Warm up
- duration: 120
arrivalRate: 5
rampTo: 50
name: Ramp up load
- duration: 600
arrivalRate: 50
name: Sustained load
각 Load Phase를 살펴 보면, name으로 구분되어 있는데
Warm up 단계에서는 “5명”의 가상의 유저가 총 60초동안, 1초마다 요청을 보내도록 설정한 것입니다.
Ramp up load 단계는, “5명”의 가상 유저로 시작해서 2분마다 점차 유저의 수를 늘려가고 최대 50명까지 유저를 늘리면서 요청을 보내는 단계입니다.
Sustained load 단계는, 50명의 가상 유저가 1초마다 5분 간 요청을 보내는 것이다. 이 단계가 stress test인 것입니다.
여기에 payload를 붙여서 외부 파일의 데이터를 가져와 테스트를 진행할 수도 있지만, 다루지는 않겠습니다.
test script 작성에 대해서는 공식 문서를 참고해주세요
CLI 사용
간단하게 cli 상으로 테스트를 진행하고 이에 대한 report를 받아볼 수 있습니다.
우선, 서버를 띄운 상태에서 다음 명령어를 입력합니다.
npx artillery quick --count 100 -n 50 http://localhost:3000
저는 로컬 환경에서 3000번 포트를 열어 서버를 띄웠는데, url 부분은 각자 맞춰서 입력해주세요.
위 명령어를 실행하면 http://localhost:3000에 부하 테스트를 실시하게 됩니다.
위에서 작성했던 script와 비슷하게,
- —count : 가상 유저의 수
- -n : 요청 횟수
- —rate : 초당 요청
즉, 해당 서버로 100명의 가상 유저가 각각 50번의 요청을 보내게 되고, 총 5000번의 요청이 서버로 전달되는 것입니다.
테스트가 끝나면, 다음과 같이 summary report를 터미널에 띄워줍니다.
응답 시간에 대한 정보를 살펴보니, 최소 2ms에서 최대 334ms까지 응답 시간이 다양하게 분포되었습니다.
중간값은 141.2ms 이고, p95와 p99는 각각 95번째, 99번째 요청에 대한 응답 시간 값입니다.
현재 스크립트를 작성하지 않았기 때문에 당연히 http 404 코드인 것을 확인할 수 있습니다.
추가로 winston를 이용하여 서버에서 API 호출할 때 마다 로그를 남길 수 있습니다.
이 외에도 다양한 옵션을 붙여서 부하 테스트를 실시할 수 있으니 문서를 참고해주세요.
Scenarios Test 진행
미리 시나리오 설정 파일을 작성하여, 실제 유저의 행동을 모방하여 부하 테스트를 진행할 수 있습니다. 이러한 시나리오를 통해 진행하는 부하 테스트가 방금 진행했던 테스트보다 의미가 있을 것입니다.
앞서 봤던 script를 이해한다면, 시나리오 설정 파일도 쉽게 작성할 수 있습니다.
loadtest.json
{
"config": {
"target": "http://localhost:3000",
"phases": [
{
"duration": 60,
"arrivalRate": 30
}
]
},
"scenarios": [
{
"flow": [
{
"get": {
"url": "/shops"
}
},
{
"post": {
"url": "/authors/signIn",
"json": {
"loginId" : "test1",
"password" : "1234"
}
}
},
{
"get": {
"url": "/shops/keyword?keywordContent=coffe"
}
}
]
}
]
}
Config Section
- target : 테스트를 진행할 어플리케이션의 url, 즉 서버 주소
- phases : 테스트 요청 시간과 비율 설정
ex) { “duration” : 60, “arriavalRate” : 30 } : 60초 동안 1초 마다 30개 요청 - defaults : 시나리오의 기본값을 설정
- payload : 외부 파일의 데이터를 보내기 위해서 사용, csv파일
Secnarios Section
- name : 시나리오 이름
- flow : 진행할 테스트의 동작을 순서대로 적으면 됩니다.
각 요청의 메소드를 적어주고, 호스트를 제외한 url를 적어줍니다.
만약 body로 보낼 데이터가 필요할 경우 위와 같이 json 형식으로 작성하면 됩니다. - match : 응답 데이터가 원하는 값이 오는 지 확인할 수 있습니다.
- weight : 시나리오에 가중치를 설정할 수 있습니다.
제가 작성한 파일에서는 “60초 동안” 매 초 “30명의 가상 유저”가 요청을 보내도록 설정했습니다. 즉 1분 동안 1800명이 접속하는 상황입니다.
저는 그냥 임의의 데이터를 직접 적어서 넣었지만, config 설정에서 payload로 미리 작성한 csv 파일을 불러와서 {{loginId}}, {{password}}로 데이터를 가져옴으로써 여러가지 예시를 테스트 해볼 수 있습니다.
~~~~{
"payload" : "./example.csv",
"fields" : ["loginId","password"]
},
"scenarios":[
{
~~~~~
"json" : {
"loginId" : {{loginId}},
"password" : {{password}},
}
~~~~~~
이렇게 작성하는 편이 실제 상황과 더 유사한 테스트이겠지만, 여기서는 생략하겠습니다.
이렇게 작성한 후 다음과 같이 명령어를 입력하여 테스트를 진행합니다.
npx artillery run loadtest.json
그러면 우리가 설정한 시나리오대로 알아서 부하 테스트를 진행하고, 이에 대한 report를 제공해줍니다!
이번에는 http 200으로 정상적으로 잘 응답이 온 것을 확인할 수 있습니다. 또한 응답 시간을 살펴보면 중간값이 16.9ms이고 p95과 p99가 32.8ms, 98.5ms로 아까보다 훨씬 빨라졌습니다.
총 5400개의 응답이 전달되었습니다. 시나리오 설정 파일을 살펴보면, 저는 한 flow에 3개의 요청을 작성했습니다. 그리고 60초 동안 1초마다 30명의 가상 유저가 하나의 flow대로 요청을 보내기 때문에 60 * 30 * 3 = 5400입니다.
그리고 해당 report를 보고 이를 분석하여 현재 어떠한 부분이 문제가 되는지를 확인합니다. 서버 오토스케일링을 설정하거나 쿼리를 개선하여 성능을 높이는 등 적절한 조치를 취하면 됩니다.
Web에서 Test Report 조회하기
npx artillery run -o myReport loadtest.json
위와 같이 테스트를 진행하면, myReport이라는 “로그 파일”이 생성될 것입니다.
이름은 마음대로 작성하셔도 됩니다.
npx artillery report myReport
위와 같이 명령어를 입력하면, 해당 report를 html 파일로 변환해줍니다.
이를 브라우저에서 실행하면 깔끔한 그래프 형태의 report를 받아볼 수 있습니다.
참고자료
https://www.perforce.com/blog/alm/what-non-functional-testing
'기타 > 기타' 카테고리의 다른 글
서버 구축 routine (0) | 2022.08.12 |
---|---|
Node.js 기본 개념 및 동작 원리 (0) | 2021.09.26 |
서브 도메인 설정 및 리다이렉션 (0) | 2021.07.04 |
도메인 설정 및 HTTPS 적용 (0) | 2021.07.04 |
MySQL 외부 접속 허용 및 phpMyAdmin 설치 (0) | 2021.07.04 |