목록 보기
JEST를 이용한 SW Test 활용해보기
기타

JEST를 이용한 SW Test 활용해보기

레모네이드
레모네이드
2021년 2월 17일

by skchoi Contents 소프트웨어 테스트는 필요한일일까 패스트캠퍼스랭귀지(FCL)의 테스트 방법소개 실제 업무에 테스트 적용해보기 소프트웨어 테스트 활용후기 소프트웨어 테스트는 필요한일일까? 개발자로서 작업이 끝나고 그 내용을 위한 테스트 코드를 작성해야 한다는 것은 꽤 귀찮은일이다. 단기적으로 보면 개발 시간이 연장될 뿐 아니라 그 효용성에 대해서도 의구심이 들기 때문이다. 거기에 더해 어차피 User Action은 전부 고려할 수 없고, 단순한 API 동작 테스트만 하는 게 과연 도움이 될까 하는 회의감도 한 몫더한다. 지금껏 제대로 동작하는 테스트를 경험해 볼 기회가 없었기에, 위와 같은 의문만 가진 채 테스트 작성을 등한시 해왔었는데, 이번 패스트캠퍼스(FCL)에서 기회가 닿아 테스트를 사용해본 후기를 공유해보려고한다. 패스트캠퍼스랭귀지(FCL)의 테스트 방법소개 먼저 패스트캠퍼스랭귀지의 테스트 컨셉과 방법에 대해 소개하고자한다. Concept 테스트 툴(Tool)은 Jest를이용한다. 테스트의 병렬성 및 속도 향상을 위해 Docker 컨테이너(DB)를 복수개 운용하고, DB를 Queue로 요청하여 테스트 별로 acquire(), release() 하도록설계하였다. 멱등성을 적용하기 위해 Fixture, Snapshot, Rollback 기능을이용하였다. 멱등성이란? (https://ko.wikipedia.org/wiki/멱등법칙) 멱등성이란 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다. 테스트의 세계에서 멱등성을적용하려면 초기 상태(Fixture: 고정된 값)가 정의되어야 한다 — 이 초기상태는 테스트와 관련된 DB, 결제, 상품 등을 설정하는것 초기 상태를 Snapshot을 찍어둔다. 테스트를 실행한다. — 이 때 초기 설정값이 변경 될 수 있다. (DB 내용 변경등) 하나의 테스트가 완료되면 Snapshot 찍어둔 것을 Rollback하여 다시 초기상태로 되돌린다. (멱등성유지) Test Flow 실제 업무에 테스트 적용해보기 패스트캠퍼스(FCL)에서 내가 맡았던 업무는 결제 관련 모듈과 쿠폰처리였다. 모두 회사의 매출과 재화에 영향이 있다 보니 조심스러운 상황 이었는데, 차근차근 테스트를 만들어 가며 진행했던 것이 도움이 많이되었다. Step 1. 테스트 파일생성 먼저 테스트는 아래와 같은 규칙으로 코드를생성한다. unittest는 (filename).unittest.js systemtest는 (filename).systemtest.js Step 2. 개발 진행 단계에서 TC작성 요구사항에 맞는 기능을 개발하면서 개발중인 API를 테스트하는 단순한 TC(Test Case)들을 추가하며진행한다. let targets = await orderDomain.findPartnershipCouponTargetList(( partnershipCouponType, now )) expect(targets.length).toBeLessThan(1) let partnershipCouponList = await couponDomain.getPartnershipCouponList(( partnershipCouponType, orderId, partnershipCouponQuantity: orderQuantity, )) expect(partnershipCouponList.length).toBe(orderQuantity) let ret = await couponDomain.updatePartnershipCoupon(( userId, orderId, orderPackageId, partnershipCouponNumber, )) expect(ret).toBe(1) Step 3. 개발 완료 단계에서 TC작성 작업이 완료되면, 개발의 본래 의도를 담은 TC와 현 단계에서 예상이 가능한 오류 및 위험요소를 체크할 수 있는 TC를작성한다. 예를 들어, 요구사항 중에 고객에게 배달이 완료된 주문중에 2주가 지난 목록들을 불러와 쿠폰을 발송하는 기능이 있는데, 개발 의도를 반영한 TC는 아래 플로우를 모두 포함해야한다. 상품 주문 → 완료 → 주문 완료 부터 2주 지난 시점으로 day 설정 → 쿠폰 리스트 얻어오기 → 얻어온 리스트 메일로발송 아래는 실제 적용된 예제코드이다. test('test sending coupon and update that information', async () => ( const merchantCipher = createMockOrderCipher() const mockPublisher = newMockPublisher(( mylightDb: db )) const orderDomain = newOrderDomain(( db, merchantCipher, publisher: mockPublisher, )) const couponDomain = newCouponDomain(( db )) let partnershipCouponType = 'wsj' let now = moment().add(16, 'd').format('YYYY-MM-DD') // 가주문을 넣고 완료상태로 만드는 것을 Fixture로 정의 하였다. // 가상 주문의 주문 완료일이 테스트를 실행한 날(today)이기 때문에, // 그로부터 16일 뒤를 nowTime으로 넘겨주어 테스트가 용이하도록 API를 구성하였다. const targets = await orderDomain.findPartnershipCouponTargetList(( partnershipCouponType, now, )) expect(targets).toBeDefined() for (const target of targets) ( const ( orderId, orderQuantity ) = target // 쿠폰을 보낼 대상이 있는지 조회한다. let partnershipCouponList = await couponDomain.getPartnershipCouponList(( partnershipCouponType, orderId, partnershipCouponQuantity: orderQuantity, )) expect(partnershipCouponList.length).toBe(orderQuantity) ) // 쿠폰을 고객 메일로 전송한다. await mockPublisher.push(( message: ( messageType: MESSAGE_TYPE_EMAIL, parameters: ( type: EMAIL_PARAMETER_TYPE_PARTNERSHIP_COUPON, partnershipCouponType, now, ), ), )) for (const target of targets) ( const ( orderId, orderQuantity ) = target // 쿠폰 전송 이후에 쿠폰 대상자를 재조회 할 시, 대상자가 없어야 한다. const partnershipCouponList = await couponDomain.getPartnershipCouponList(( partnershipCouponType, orderId, partnershipCouponQuantity: orderQuantity, )) expect(partnershipCouponList.length).toBe(0) ) )) 그밖에 예상되는 위험요소는 아래와 같은 것들이있었는데, 주문 완료 2주전에 쿠폰이 발송되면안된다. 쿠폰이 제대로 발송 되어야한다. 발송한 쿠폰이 다시 발송 되면안된다. 남은 쿠폰이 없는 경우에 대한 처리를해야한다. 복수개의 패키지를 구매 시 수량 만큼 다른 쿠폰이 지급되어야한다. 이를 위해 내가 추가한 쿠폰 테스트목록이다. test(check either setting partnership coupon type in order package table is well ornot) test(find targets for sending partnership coupon) test(test coupon should not be shipped until twoweeks) test(check table about coupon updated state to assignedwell) test(test order 2 same package and send 2 different coupon) test(test alert error when there is notcoupon) Step 4. 작업내용Push 테스트 작성이 완료되고 작업된 내용을 push 해야하는데, husky라는 Hook 기능을 이용하여, 코드 push시 자동으로 모든 test를 실행하게 하였고, 실패시 push가 되지 않도록 구현하였다. (내가 작성한 코드가 다른 기능에 영향을 주지 않는지 등을 더블 체크 할 수 있어 안정화에 도움이되었다.) "husky": ( "hooks": ( "pre-push": "yarn test:push" ) ) 소프트웨어 테스트 활용후기 테스트를 제대로 사용해보면서 느낀점은 내가 생각했던 것 보다 장점이 많았다는것이다. 모든 케이스를 고려할 수도, 테스트화 시킬수도 없다고 믿었기에 실효성에 대해서 의문이 많았었는데, 이번 기회를 통해 적어도 한가지는 보장 받을 수 있겠다는 믿음이생겼다. 내가 처음 개발단계에서 의도한 기능이 정상 동작 하는지, 그리고 다른 수정이 그 기능의 의도를 해치지 않는지를 매번 확인할 수 있다는 것이다. 특히 협업을 하면서 다른 사람의 코드와 의도를 모두 파악할 수 없기에 적어도 내 수정분이 다른 테스트를 fail시키지 않는다는 보장은 팀 전체 개발의 효율성 측면에서 강력한 효과를 발휘 한다는 생각이들었다. 앞으로 테스트에 관련된 노하우나 기술들은 계속 발전 하겠지만, 현재 FCL 개발팀에서 추구하는 방향은 최소한 개발한 모듈의 책임 범위 한에서는 테스트를 작성해야 한다는 것이다. 추후 데이터가 더 쌓이고 빈번히 발생하는 인적 실수 등의 항목들이 유형화될 수 있다면 모듈의 책임을 넘어선 부분까지 테스트의 효용성과 생산성이 올라갈 것이라고 기대하고있다.

댓글 0

댓글을 작성하려면 로그인이 필요합니다.

댓글을 불러오는 중...