11. 노드 서비스 테스트하기

진영민·2022년 9월 11일
0

Node.js 교과서

목록 보기
10/13

해당 글은 Node.js 교과서의 내용을 요약, 정리한 글입니다.

준비

jest

$npm i -D jset

테스팅 툴은 개발 시에만 사용하므로 -D옵션을 사용한다.

package.json에는 test라는 명령어를 등록해 둔다.

//package.json
{
	"name":...
    "version":...
    ...
    "scrpits":{
    	"start":...
        "test":"jest"
    },
    ...
}

이 후 폴더 안에 middlewares.test.js를 만든다.
테스트용 파일은 파일명과 확장자 사이에 test나 spec을 넣으면 된다.

//middlewares.test.js
test('1+1',()=>{
    expect(1+1).toEqual(2);
})
//결과
> nodejs@1.0.0 test
> jest

 PASS  testing/middlewares.test.js
  √ 1+1 (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.822 s
Ran all test suites.

유닛 테스트

//middlewares.test.js
const { isLoggedIn,isNotLoggedIn} = require("./middlewares");

describe('isLoggedIn',()=>{
    const res={
        status:jest.fn(()=>res),
        send:jest.fn(),
    };
    const next = jest.fn();

    test('로그인되어 있으면 isLoggedIn이 next를 호출해야 함',()=>{
        const req={
            isAuthenticated:jest.fn(()=>true),
        };
        isLoggedIn(req,res,next);
        expect(next).toBeCalledTimes(1);
    });
    
    test('로그인되어 있지 않으면 isLoggedIn이 에러를 응답해야 함',()=>{
        const req={
            isAuthenticated:jest.fn(()=>false),
        };
        isLoggedIn(req,res,next);
        expect(res.status).toBeCalledWith(403);
        expect(res.send).toBeCalledWith('로그인 필요');
    });
});

여기서 describe함수는 test들을 그룹화 해주는 역할을 한다.

이렇게 작은 단위의 함수나 모듈이 의도된 대로 정확히 작동하는지 테스트하는 것을 유닛 테스트라고한다.

라우터의 한 부분을 다른 파일로 분리하여 테스트하는 것도 가능하다.
주의할 점은 async 함수는 await을 붙여야 컨트롤러가 실행 완료된 후 expect함수가 실행된다는 점이다.

모킹

테스트 코드에서의 객체는 실제 객체일 필요가 없다.
따라서 가짜 객체나 가짜 함수를 생성해서 넣어 주기도 하는데, 이를 모킹이라 한다.

jest는 모듈도 모킹할 수 있다.

jest.mock('../models/user');
const User = require('../models/user');

jest.mock에서는 모킹할 메서드에 mockReturnValue라는 메서드를 넣는다.이 메서드로 반환값을 지정할 수 있다.

테스트 커버리지

전체 코드 중에서 어떤 부분이 테스트되고 어떤 부분이 테스트되지 않는지 확인하는 방법

//package.json
{
	...
  	"scripts": {
      	"start":"nodemon app",
      	"test": "jest",
      	"coverage":"jest --coverage"
    },
}

$npm run coverage
테스트 결과가 출력되고 추가적으로 표가 하나 더 출력된다.

% Stmts
//구문 비율

% Branch
//if문 등의 분기점 비율

% Funcs
//함수 비율

% Lines
코드 줄 수 비율

Uncovered Line
커버되지 않은 줄 위치

통합 테스트

$npm i -D supertest
supertest를 사용하기 위해서는 app객체를 모듈로 만들어 분리해야 한다.
app.js파일에서 app객체를 모듈로 만든 후, server.js에서 불러와 listen한다.

server.js는 app의 포트 리스닝만 담당한다.

package.json을 상황에 맞게 수정한다.

  "scripts": {
    "start":"nodemon server",
    "test": "jest",
    "coverage":"jest --coverage"
  },

통합 테스트에서는 데이터베이스 코드를 모킹하지 않는다. 따라서 테스트용 데이터베이스를 따로 만드는 것이 좋다.

//routes/auth.test.js
const request = require('supertest');
const { sequelize } = require('../models');
const app = require('../app');

beforeAll(async ()=>{
	await sequilize.sync();
});

describe('POST /login',()=>{
	test('로그인 수행', (done)=>{
    	request(app)
        .post('/auth/login')
        .send({
        	email: 'jinmin645@gmail.com',
            password: '12345678',
        })
        .expect('Location','/')
        .expect(302, done);
    });
});

beforeAll

테스트를 실행하기 전에 실행하는 함수
자매품으로 afterAll, beforeEach, afterEach등이 있다.

부하 테스트

$npm i -D artillery
$npm start

$npx artillery quick --count 100 -n 50 http://localhost:8001

localhost:8001에 빠르게 부하 테스트를 하는 방법.
--count는 가상 사용자 수를 의미한다.
-n옵션은 요청 횟수를 의미한다.

request latency가 중요한데, 보통 median과 p95값의 차이가 크지 않으면 좋다.

시나리오 테스트

//loadtest.json
{
    "config":{
        "target":"http://localhost:8001",
        "phases":[
            {
                "duration":60,
                "arrivalRate":30
            }
        ]
    },
    "scenarios":[{
        "flow":[
            {
                "get":{
                    "url":"/"
                }
            },{
                "post":{
                    "url":"/auth/login",
                    "json":{
                        "email":"jinmin645@gmail.com",
                        "password":"12345678"
                    }
                }
            },{"get":{
                "url":"/"
                }
            }
        ]
    }]
}

target: 목표 서버
phases.duration: 60초 동안
phases.arrivalRate: 매 초 30명의 사용자
scenarios대로 동작한다.

profile
코린이

0개의 댓글