-
소프트웨어 테스팅
프로그램 테스트
- 의도적으로 프로그램을 사용하기 전 결함을 발견하는 것이다.
- 인공적인 데이터를 사용한다.
- 테스트는 테스트에 한해서만 에러를 보여준다.
- V&V가 테스트의 대부분이다.
- 테스트 대상
- 소프트웨어 요구사항
- 에러/실수
- 결함/버그 → 검증 단계에서 주로 발생
- 실패 (결함의 결과)
- 검증 및 확인
- Verifacation
- 요구사항 명세대로 만들었는지 확인
- 모든 요구사항마다 1개 이상의 테스트가 존재해야한다.
- Validation
- 사용자의 실 요구에 잘 맞는지 확인
- 의도적으로 결함을 드러내도록 테스트한다.
- 시스템이 사용되는 상황을 예상해서 테스트 케이스를 작성한다. → 의도대로 동작하는지?
- validation test
- 시스템의 정확한 수행 여부를 테스트 함.
- 정상 데이터 활용
- defect test
- 소프트웨어 인스펙션(점검)
- Inspection
- 정적 확인 → 코드분석, 설계 분석
- 도구 기반의 문서와 코드 분석
- Testing
- 동적 확인 → 시스템 기능, 행동, 상호작용 점검
- 테스트 데이터를 활용
- 테스트 케이스
- 기능이 추가되거나 수정되지 않는 이상 그대로 사용한다.
- 예상 결과와 실제 결과를 비교하여 보고서를 작성하고 에러를 수정한다.
- 테스트 단계
- 개발 테스트
- 시스템 개발 중 버그와 결함을 찾기 위해 테스트
- 릴리즈 테스트
- 별도의 테스트 팀이 완성 버전을 릴리즈 하기 전에 테스트
- 요구사항에 맞는지 점검한다.
- 사용자 테스트
- 사용자들이 실제 사용 환경에서 동작하는지 확인한다.
- Acceptance 테스팅은 사용자 테스트의 한 유형이다.
- 이 테스트를 통해 소프트웨어를 전달 받을지 결정한다.
개발 테스트
- 시스템 개발 팀에 의해 수행 되는 모든 테스트
- 유닛 테스트
- 메서드나 객체, 속성 등의 기능 테스트를 수행한다.
- 테스트 대상은 개별적인 기능-동작에 대해 테스트한다.
- 객체클래스 테스팅
- 모든 메서드, 속성과 가능한 상태에 대해 테스트한다.
- 상속 등으로 인해 부모-자식 간의 경계가 불분명하다.
- 테스트 자동화
- JUnit 등을 활용한 테스트 자동화가 필요하다.
- Setup 파트에서 테스트케이스에서 테스트의 예상되는 입출력을 정의해야한다.
- Call 파트에서 객체나 메서드를 테스트한다.
- Assertion 파트에서 테스트의 결과와 예상안을 비교해야한다.
- 테스트 케이스
- Validation : 시스템이 내 의도대로 동작하는지 확인.
- Verification : 결함이 테스트 케이스를 통해 드러나는지 확인.
- 비정상 입력에 대해 시스템이 적절한 예외 처리 등으로 대처하는지 확인.
- 테스트 전략
- 분할 테스트
- 특정 집단의 공통된 특성을 가진 입력은 동일한 테스트로 본다.
- 대표되는 테스트 케이스만 테스트한다.
- 가이드라인 기반 테스트
- 테스트 케이스를 선정하기 위한 테스트 가이드 라인을 사용한다.
- 가이드 라인은 이전의 에러 경험을 반영한다.
- 경계 테스트
- 결함을 확인하기 위함
- 데이터 범위의 경계 근처의 데이터로 테스트한다.
- 테스트 절차 가이드라인
- 하나의 값 만을 가지는 시퀀스로 테스트한다.
- 테스트 마다 다른 크기로 테스트한다.
- 시퀀스의 가장자리와 중간의 원소가 테스트되도록 유도한다. → 경계 테스트
- 예시
- 시스템의 모든 오류를 생성시키는 입력 선택
- 버퍼 오버플로우를 유도
- 같은 입력을 여러 번 반복
- 유효하지 않는 출력 생성을 유도
- 계산 결과의 데이터의 양, 크기를 극단적으로 줄이거나 늘린다.
- 컴포넌트 테스트
- 객체, 메서드 들의 집합인 컴포넌트가 제대로 동작하는지 테스트한다.
- 연동- 상호작용 테스트이다.
- 인터페이스를 통해 사용한다.
- 유닛 테스트는 완료되었다고 가정한다.
- 연동 시의 정상동작과 비정상 동작을 확인한다.
- 인터페이스 테스팅
- 인터페이스 오류
- 인터페이스 오용
- 인터페이스 오해
- 인터페이스에 대한 명세를 잘못 이해하고 호출하여 발생
- 개발자 간 가정이 다를 수 있다.
- 따라서, 설계 시점에서 정의해야 한다.
- 타이밍 오류
- 공유 메모리나 메시지 전달 인터페이스 사용 시 발생
- produce → consump 테스트가 이루어져야함
- 인터페이스 테스트 가이드라인
- 시스템 규모에 따라 컴포넌트가 없을 수도 있다.
- 데이터의 양 끝을 전달 → 경계 테스트
- 널 포인터 전달
- 고의적으로 컴포넌트가 실패하는 테스트 설계 및 전달
- 스트레스 테스트 사용
- 시스템 테스트
- 컴포넌트를 통합하여 하나의 시스템으로 동작하는지 테스트한다.
- 유닛테스트, 컴포넌트 테스트를 통과한 이후 테스트한다.
- 시스템 돌발 상황도 테스트한다.
- 외부 프레임워크도 통합하여 테스트한다.
- 별개의 테스팅 팀을 두기도 한다.
- 유즈케이스 테스트
- 유즈케이스 기반으로 시스템을 테슽한다.
- 별개의 테스팅 팀을 두기도 한다.
테스트 전략
- 과도한 테스트는 현실적으로 불가능
- 따라서 현실적인 범위를 지정한다.
- 상황에 맞거나 안맞는 입력을 모두 테스트한다.
- 기능 간의 조합도 테스트한다.
- 하향식 통합 테스트
- Main 모듈을 테스트하기 위해 임시 서브 모듈과의 연동을 테스트한다.
- 임시적 서브 모듈을 Stub 이라 한다.
- 장점
- Main의 문제를 조기 발견
- 뼈대가 조기 완성
- 단점
- Stub 제작에 대해 추가 비용 발생
- 서브 모듈에 대한 정확한 출력 판단이 불가
- 상향식 통합 테스트
- 서브 모듈을 테스트 하기 위해 임시 메인 모듈과의 연동을 테스트한다.
- 임시 메인 모듈을 Drivers 라고 한다.
- 장점
- 서브 모듈의 문제 조기 파악
- 기능이 완성되어 있어 테스트가 쉽다.
- 단점
- Drivers 모듈 제작에 추가 비용 발생
- 메인이 구현될 때 까지 전체 서브 모듈이 독자적 기능 불가
릴리즈 테스트
- 개발팀이 외부에서 사용할 시스템의 특정 버전을 테스트한다.
- 기능-성능-신뢰도-문제 발생에 대한 테스트를 수행한다.
- 일반적으로 시스템 명세 기반의 블랙박스 테스트이다.
- 시스템 테스트의 한 형태이다. → 대상 동일
- 차이점
- 별도의 팀이 테스트한다.
- 시스템 테스트는 개발팀이 버그를 찾는 결함 테스트에 초점을 맞춘다. (Defect Test)
- 릴리즈 테스트는 테스팅 팀이 외부 환경에서의 요구사항에 맞는지 확인한다. (Validation)
- 요구사항 기반 테스트
- 요구 사항 기반의 테스트 케이스를 작성한다.
- 예시
- 시스템 로깅에 의한 인증
- 다운로드, 업로드
- 스케줄링
- 암호화-복호화
- 조회 및 수정
- 연결
- 호출
- 성능 테스트
유저 테스트
- 사용자가 입력을 제공하고 시스템 테스트에 관한 의견을 전달한다.
- 시스템-릴리즈 테스트 수행 이후에도 필수적으로 수행해야한다.
- 사용자의 환경 변화가 시스템에 영향을 미칠 수 있다.
- 종류
- 알파 테스트
- 베타 테스트
- 소프트웨어의 특정 버전을 사용자에게 공개하여 테스트한다.
- 인수 테스트
- 맞춤형 제품에 대한 테스트이다.
- 고객의 환경에 배치하여 테스트하고 인수를 결정한다.
- 애자일 기법에서의 인수 테스트
- 사용자가 개발팀의 한 부분이다.
- 사용자에 의해 정의된 테스트를 통해 통합을 결정한다.
- 자동화된 테스트를 수행한다.
- 별도의 인수 테스트를 거치치 않는다.
블랙박스 테스트, 화이트 박스 테스트
- 블랙박스
- 기능의 동작 확인
- 제대로 동작하는지 확인한다.
- 모든 테스트 단계에서 적용할 수 있다.
- 높은 단계에서 적합하다.
- 화이트박스
- 소스코드나 설계을 확인
- 어떻게 동작하는지 확인한다.
- 코드 기반 테스트 이므로 낮은 단계나 작은 규모에 적합하다.
소프트웨어 유지보수
소프트웨어 변화
- 변화의 핵심은 기존 시스템의 변화를 적용하고 관리하는 것이다.
- 필수적인 소프트웨어 변화
- 새로운 요구사항
- 비즈니스 환경의 변화
- 오류 발견
- 새로운 하드웨어 장비
- 성능과 안정성의 개선
- 변화의 중요성
- 대부분의 조직에서 새 시스템 개발보다 유지 보수에 더 큰 투자를 한다.
- 소프트웨어 예산의 대부분이 기존 시스템을 변화시키고 진화시키는것에 있다.
변화와 서비스
- 변화(진화) 단계
- 시스템에 대해 새로운 요구사항이 제안되고 구현된다.
- 서비스 단계
- 기능적인 요소를 유지하면서 버그를 수정하고 소프트환경 변화를 적용한다.
- 새로운 기능을 추가하지 않는다.
- 폐기 단계
- 소프트웨어 자체는 유지될 수 있으나 추가적인 변화가 이루어지지 않는다.
진화 프로세스
- 진화 단계에서 특별한 기준은 없다.
- 대신, 소프트웨어 타입, 개발 프로세스, 개발자의 능력에 의존하여 결정한다.
- 변화 제안
- 시스템 진화의 핵심 절차이다.
- 변화에 영향을 받는 컴포넌트
- 비용
- 변화에 대한 영향 측정
- 시스템 생명 주기의 전반에 걸쳐 지속된다.
- 새 시스템
- 변화 식별 프로세스
- 변화 제안
- 소프트웨어 변화 프로세스 (변화 적용)
- 변화 구현
- 요구사항 명세와 설계 문서가 있다면 이 문서들 또한 진화 과정 중에 수정해야한다.
- 설계, 구현, 테스트 같은 개발절차의 반복이다.
- 개발과의 차이점
- 기존의 프로그램에 대해 이해해야할 필요가 있다.
- 시스템 구조
- 시스템 기능
- 시스템에 미치는 영향
- 긴급한 변경
- 심각한 오류
- 시스템 환경의 변화
- 비즈니스 환경의 급격한 변화
- 절차
- 변화 요구
- 코드 분석
- 코드 수정
- 코드 적용
- 애자일 기법에서는?
- 애자일 기법은 점증적 개발에 기반하므로 서비스 → 진화의 단계가 매끄러워야 한다.
- 문제점
- 개발팀과 유지보수 팀의 프로세스가 다를 경우
- 요구사항이나 설계 관련 자세한 문서가 없을 수 있다.
- 자동화 테스트 개발을 선행해야 할 수 있다.
- 코드 개선을 선행해야 할 수 있다.
레거시
- 오래된 언어, 기술로 구성된 오래된 시스템이다.
- 구형 하드웨어, 프로세스에 의존적일 수 있다.
- 사회기술적 요소와 엮여있을 수 있다.
- 레거시 시스템의 교체는 위험하고 많은 비용이 든다.
- 시스템 명세가 부족할 수 있다.
- 시스템과 비즈니스 환경 및 절차가 매우 적합하게 맞아 떨어질 수 있다.
- 문서화 되지 않은 비즈니스 정책 등이 시스템에 내장되어있을 수 있다.
- 새 소프트웨어 개발에 시간-비용 적인 문제가 들 수 있다.
- 레거시 시스템의 변경 또한 많은 비용이 든다.
- 프로그래밍 스타일이 일관되지 않을 수 있다.
- 구식 언어이므로 개발 인력이 많지 않을 수 있다.
- 시스템 문서가 불충분 할 수 있다.
- 시스템 구조 품질이 저하될 수 있다.
- 프로그램이 특정 기계 등에 최적화 되어 이해하기 어려울 수 있다.
- 데이터 처리에 오류가 있을 수 있다.
- 레거시 시스템의 관리
- 낮은 품질, 낮은 가치
- 낮은 품질, 높은 가치
- 높은 품질, 낮은 가치
- 상용 프로그램으로 대체한다.
- 변화 비용이 비싸질 경우 폐기한다.
- 아니라면, 유지한다.
- 높은 품질, 높은 가치
- 기존의 시스템을 그대로 사용하고 유지보수한다.
소프트웨어 유지보수
- 유지보수 기준
- 오류 수정
- 버그나 취약점을 수정한다.
- 요구사항을 만족시킨다.
- 환경 변화 적응
- 기능 추가 및 수정
- 예방적 유지보수
- 오류 발생을 방지하기 위해 코드를 변화시킨다.
- 유지보수 비용
- 유지보수 팀이 개발 팀과 다를 수 있다.
- 이에 따라 이해 비용이 필요하다.
- 개발 팀에 대한 혜택이 없어 개발 팀이 유지보수 품질을 신경쓰지 않을 수 있다.
- 유지보수는 비선호된다.
- 프로그램이 오래될 수록 변경이 어려워진다.
- 시스템 구조 품질이 저하되면 변경이 어렵다.
- 이에 따라 유지보수 선호도가 낮아진다.
- 해당 시스템의 유지보수에 대한 전문가 수가 감소한다.
- 위 단계가 반복된다.
- 유지보수 예측
- 시스템의 어떤 부분이 문제를 일으키고 큰 비용을 소모하는지에 연관된다.
- 시스템 유지보수성(복잡도)이나 유지보수 비용, 시스템 변화를 예측한다.
- 시스템의 변화는 시스템의 구조 품질을 낮추어 다음 변화 난이도를 증가시킨다.
- 변화량의 예측은 시스템과 외부 환경 간의 관계를 확인하고 이해해야한다.
- 환경의 변화가 시스템의 동작에 영향을 미칠 수 있다.(딱 맞아떨어지는 시스템일 경우 영향이 크다.)
- 환경과의 관계 판단 기준
- 시스템 인터페이스의 개수와 복잡도
- 특정 기관의 정책 절차에 의한 요구사항
- 비즈니스 프로세스
- 복잡도 측정(코드 수준) 기준
- 제어 구조 복잡도
- 데이터 구조 복잡도
- 메서드나 모듈, 객체의 크기
- 프로세스 측정 기준
- 버그나 요구사항 등의 수정 요구 횟수
- 영향 분석에 필요한 평균 시간
- 변경 요구 구현에 소요되는 평균 시간
- 추가적으로 대기 중인 수정 요구
- 위와 같은 기준에 적용된다면 유지보수성이 하락할 수 있다.
- 소프트웨어 재공학
- 레거시 시스템의 유지보수를 위해 시스템이나 컴포넌트를 재구조화 한다.
- 재공학을 통해 유지보수 비용을 낮춘다.
- 이점
- 프로세스
- 코드 변환
- 역공학
- 추상적인 구조 품질 향상
- 프로그램 모듈화
- 데이터 재공학
- 리팩토링
- 프로그램 구조를 향상시켜 품질 저하를 늦춘다.
- 예방적인 성격을 띈다.
- 기능 추가가 목적이 아니다.
- 재공학과 리팩토링
- 재공학
- 유지보수 비용의 증가에 따라 실행한다.
- 구조, 언어, 문서, 데이터구조가 바뀔 수 있다.
- 개발자를 위한 리팩토링을 포함한다.
- 리팩토링
- 개발 및 진화 과정 전반에 걸쳐 구조 품질 저하 및 비용 증가를 방지하기 위해 실행한다.
- Bad Smells
- 중복 코드
- 긴 메서드
- 스위치 케이스 문
- 데이터 집합
- 추측 기반의 일반성