[TIL] Software Testing

🍉effy·2022년 2월 17일
0
post-thumbnail

01. What is Software Testing?

  • 제대로 된 소프트웨어를 개발했는가?
  • 소프트웨어를 제대로 개발했는가?

01-2. Why test?

  • 결함 확인
  • 사전 방지 : Test 를 해봄으로써 고객 입장에서 어떤 문제가 발생하는 지 미리 캐치 할 수 있다
  • 시간 절약
  • 구조 개선 : 결함을 미리 확인하고 사전에 방지하는 과정에서 구조를 개선
  • 품질 개선 : 전체적인 품질이 개선되는 효과
  • 확장성 : 이러한 과정을 거치면서 확장성 있는 시스템 구축

02. Testing Pyramid

![]

  • Google Test Automation Conference 에서 제안된 테스트 피라미드
  • 시스템을 테스트 할 때 크게 3가지 방법으로 나눌 수 있다
  • 전체 테스트 비중을 이와 같은 수치로 구현하는 것이 권장된다
- E2E(UI) Testing - 10
- Integrating Testing - 20%
- Unit Testing - 70%

02-1. Unit Test?

  • Unit Test 란?
    내가 작성한 코드의 가장 작은 단위인 함수를 테스트하는 메소드
    컴퓨터 프로그래밍에서 소스코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차
    => 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 말한다
    가장 쉬우며 효과가 좋다.
    => 내가 작성한 로직을 테스트하는 유닛 테스트 코드를 짜서 테스트하는 방법, 어떤 기능이 실행되면 어떤 결과가 나오는지 테스트

예를 들어 프론트의 경우 버튼을 추가해서 이벤트를 처리하는 신규 로직을 구현할 때마다 화면에 띄워서 테스트해야 하기 때문에 시간이 많이 소요된다.
👋🏻 유닛 테스트는 빠르고 비용이 싸므로 개발할 때 필수적으로 작성해야 한다.

📌 Unit Test 의 장점

  • Unit Test 는 UI Test, Integration Test 보다 비용이 싸다. 왜냐면 UI Test 는 백엔드 서버와 프론트를 연동해서 사람이 직접 테스트 (인력이 든다) 하지만, 유닛 테스트는 사람이 스크립트로 한꺼번에 자동으로 실행하기 때문이다.
  • 또한 타 테스트에 비해 실행 속도가 매우 빠르다. 유닛 테스트를 활용하면 하루에도 배포를 여러번 할 수 있어 개발 및 배포 속도에 중요한 영향을 주기 때문에 개발 할 때 최대한 활용하는 것이 좋다
  • 새로운 기능을 구현할 때 유닛 테스트를 잘 작성해놓으면 중장기적으로 유지보수가 쉬운 장점 이 있다. 이전에 통과했던 테스트 집합을 가지고 버그를 찾기 위해서 이전에 테스트 된 유닛테스트를 반복하는 것을 regression 테스트라고 하는데 유닛 테스트만 반복하면 되기 때문에, regression 테스트도 반복적으로 수행할 수 있다
  • 유닛 테스트를 잘 짜놓는다면 유닛테스트가 되었던 코드에서는 버그가 거의 발견되지 않고, 대부분 버그가 발생되는 경우 유닛테스트가 없어서 발생하는 경우가 많으며 만약 사후에 발견된 버그에서도 버그를 수정한 후 유닛테스트를 작성해놓으면 버그를 방지할 수 있다!

02-2. End-To-End Testing / UI Testing

  • 크롬 브라우저를 띄운 다음, 내가 만든 검색 페이지로 들어가서 검색을 해보고 검색한 내용이 제대로 나오는 지 화면상에서 확인하거나 직접 회원가입을 해보고 회원 가입 후에 로그인 되는지 직접 브라우저 상에서 값을 입력해서 테스트하는 방법
  • UI testing 이 가장 어렵고 까다롭다
  • Manual Testing 은 실행하기 쉽다는 장점이 있지만 비용이 많이 들고 부정확 하며 실행 기간이 오래걸린다.
  • 자동화 할 수 있지만 UI Testing 은 자동화 하기가 가장 까다롭고, 또 실행하기도 까다롭다
  • 대표적인 TOOL : Cypress

02-3. Integration Testing (통합 테스트)

  • 모듈을 통합하는 과정에서 모듈 간의 호환성을 확인하기 위해 수행되는 테스트
  • 일반적으로 애플리케이션은 여러 개의 모듈 들로 구성이 되고, 모듈들끼리 메세지를 주고 받으면서 (함수 호출) 기능을 수행한다
  • 그렇기에 통합된 모듈들이 올바르게 연계되어 동작하는지 검증이 필요하다. 이러한 목적으로 진행되는 테스트!
  • 유닛 테스트처럼 독립적인 기능에 대한 테스트가 X, 웹 페이지로부터 API 를 호출하여 올바르게 동작하는 지 확인하는 테스트 이다.
  • 최소 두개 이상의 클래스 또는 서브 시스템의 결합을 테스트 하는 방법
  • 예를 들면 장고로 서버를 띄우고, 모델 클래스와 결합하여 데이터베이스 시스템과 연동한 테스트
  • PostMan 또는 Httpie 로 호출해서 Json response 가 제대로 출력되는지 확인
  • Integration Testing 이 E2E Testing 다음으로 공수가 많이 든다

📝 So... unit test 작성의 필요성

해당 부분만 독립적으로 테스트하기 때문에 어떤 코드를 리팩토링 하여도 빠르게 문제 여부를 확인 가능!
-Testing 에 대한 시간과 비용을 절감할 수 있다

  • 새로운 기능 추가 시에 수시로 빠르게 테스트 할 수 있다
  • 리팩토링 시에 안정성을 확보할 수 있다
  • 코드에 대한 문서가 될 수 있다

**그렇기 때문에 실무에서는 단위 테스트를 선호, 요즘 많이 사용되는 TDD (Test-Driven Development, 테스트 주도 개발) 에서 얘기 하는 테스트도 단위 테스트, Unit Test 를 의미한다. 우리는 이로써 우리가 작성한 테스트 코드를 수시로 빠르게 돌리면서 문제를 파악할 수 있다!

🤔 But... unit test 의 문제점은 없을까?

어떤 객체가 자체적으로 모든 일을 처리 한다면 문제가 없겠지만, 일반적인 애플리케이션에선 1개의 기능을 처리하기 위해 다른 객체들과 메세지를 주고 받아야 한다. 하지만 단위테스트는 해당 모듈에 대한 독립적인 테스트이기 때문에 다른 객체와 메세지를 주고 받는 경우에 문제가 발생한다.

---> 그렇기 때문에 다른 객체 대신에 Mock Object ( 가짜 객체 ) 를 주입해서 어떤 결과를 반환하라고 정해진 답변을 준비 시켜야 하는데, 이를 stub 이라고 한다
( 예를 들어, 데이터베이스에 새로운 데이터를 추가하는 코드를 테스트 한다고 할 때 Mock Database 를 주입해서 insert 처리 시에 반드시 1을 반환하도록 해주는 것)

😮 그렇다면 좋은 unit test 는?

일반적으로 요구 사항은 계속해서 변하고 그에 맞춰 코드는 변경되어야 한다. 하지만 코드가 변경 될 때마다 버그가 발생할 수 있는데, 좋은 테스트 코드가 있으면 변경된 코드를 검증함으로써 이를 해결할 수 있다. 또한 실제 코드가 변경이 되면 테스트 코드 또한 변경이 필요할 수 있는데 아래처럼 가독성 있게 작성해야 한다.

  • 1개의 테스트 함수에 대해 assert 를 최소화 할 것
  • 1개의 테스트 함수는 1가지 개념 만을 테스트 할 것

📕 테스트 코드의 FIRST 규칙

  1. Fast - 테스트는 빠르게 동작하고 자주 돌릴 수 있어야 한다
  2. Independent - 각각의 테스트는 독립적이며 서로 의존해서는 안된다
  3. Repeatable - 어느 환경에서도 반복이 가능해야 한다
  4. Self-Validating - 테스트는 성공 또는 실패로 boolean 값으로 결과를 내어 자체적으로 검증이 되어야 한다
  5. Timely - 테스트는 적시에 즉, 테스트 하려는 실제 코드를 구현하기 직전에 구현해야 한다

TDD (테스트 주도 개발)?

  • 설계 이후 코드 개발 및 테스트 케이스를 작성하는 기존의 개발 프로세스와는 다르게 테스트 케이스를 작성한 후, 실제 코드를 개발하여 리팩토링 하는 절차를 따른다.
  • 책을 쓴다고 가정하자. 책을 처음 쓸 때 목차를 구성하고, 각 목차에 맞는 내용을 구상하며 작성하고 고쳐쓰기를 반복한다. 이 과정을 TDD 에 비유 한다면 목차 구성은 테스트 코드 작성 , 초안 작성은 코드 개발 , 고쳐쓰기는 리팩토링 에 해당한다.
  • 반복적인 검토, 수정을 통해 고품질의 소프트웨어를 만들 수 있다!

TDD 개발 주기

  • Red : 실패하는 테스트 먼저 작성
  • Green : 테스트 코드를 성공시키기 위한 실제 코드 작성
  • Blue : 중복 코드 제거, 리팩토링 수행

🧐 TDD 는 어떤 상황에서 해야 할까?

  • 처음 해보는 프로그램 주제일 경우에 한다. 불확실성이 높을 때
  • 고객의 요구 조건이 바뀔 수 있는 프로젝트 일 경우
  • 코드 수정이 많이 필요하다고 생각되는 경우
  • 개발은 내가 했지만, 또다른 누군가가 유지보수 할 지 모르는 경우

📌 즉 불확실성이 높을 때 TDD 를 하면 된다.

TDD 의 대표적인 TOOL 'JUnit'

  • What is 'Junit'?
    전 세계적으로 가장 널리 사용되는 'Java 단위 테스트 프레임워크'

👩🏻‍💻 TDD 의 장점

  • 피드백의 증가

  • 협력 증진 : 공유가 쉬워지기 때문에 다른 사람의 코드에 쉽게 접근이 가능하고 빠른 이해가 가능하다. 그러므로 다른 이의 코드의 의도를 확인, 이해 할 수 있다는 점
    ---> 이 둘을 동시에 증진시킨다.

  • 보다 튼튼한 객체 지향적인 코드 생산 : TDD 는 코드 재사용 보장을 명시하므로 TDD 를 통해 소프트웨어 개발 시 기능별 철저한 모듈화가 이루어진다.

  • 재설계 시간의 단축 : 테스트 코드를 먼저 작성하기 때문에 개발자가 지금 무엇을 해야하는지 분명히 정의하고 개발을 시작하게 된다(목차 과정처럼). 내용을 구상하며 작성하면서 다른 예외사항에 대해 생각해 볼 수 있고, 이는 전반적으로 개발 진행을 매끄럽게 할 수 있다.

  • 디버깅 시간의 단축 : 특정 버그를 쉽게 찾아낼 수 있다.

  • 테스트 문서의 대체 가능 : TDD 를 하게 될 경우 테스팅을 자동화 시킴과 동시에 정확한 테스트 근거를 산출 할 수 있다.

  • 추가 구현의 용이함 : 개발이 완료된 소프트웨어에 어떤 추가 기능을 구현할 때 가장 우려되는 점은 추가 기능이 기존 코드에 어떠한 영향을 미칠 것인가이다. 하지만 TDD 의 경우 자동화 유닛 테스팅을 전제하므로 테스트 기간을 획기적으로 단축시킬 수 있다.

😅 수많은 장점을 갖고 있는 TDD.. 개발 방식의 단점!

  • 생산성의 저하
    : 개발 속도가 느려진다.. 왜냐하면 처음부터 2개의 코드를 짜야하고 중간중간에 테스트를 거치며 고쳐나가야 하기 때문이다.

  • 그러기 때문에 실제 서비스 개발시, 소프트웨어의 품질보다는 납기일 준수가 훨씬 중요하기 때문에 TDD 방식을 잘 사용하지 않는다.

profile
Je vais l'essayer

0개의 댓글