Program Testing은 프로그램이 의도하는 대로 작동, 결함을 발견하기 위해서 하는 것이다.
어떤 것을 테스트 하는지를 기준으로 보면 Validating Testing, Defect Testing이 있다.
Validating Testing은 사용자의 요구사항을 충족함을 보이고, 의도한 대로 시스템이 작동하는지 보이는 것이다.
Defect Testing은 잘못된 동작, 명세와 일치하지 않는 결함을 발견. 잘못 동작하도록 하여 결함을 노출시킨다. 결함을 찾는 것!
Q) 이러한 Testing을 어떻게 해서 어떤 것을 확인하면 되나요?
artificial data를 사용하여 프로그램을 실행하고, 테스트 결과로부터 오류와 비기능적 속성을 확인한다.
프로그램 품질 보장, 결함을 발견하기 위해서는 Inspection과 Testing이 있다.
Software Inspection: 정적 시스템 Verification으로, 코드실행없이 아티팩트를 검사하는 단계(명세와 일치하는지 등등. 문서와 코드를 검사)
Software Testing: 시스템의 동작을 관찰, 테스트 데이터 활용. 비기능적 요구사항 또한 체크 가능
(요즘은 위에 두 개 다 IDE에서 잘 지원해준다)
Software Testing을 더 자세히 살펴보자.
Software Testing은 크게 보면 Development Testing, Release Testing, User Testing이 있다.
Development Testing은 뭔가요?
개발 중에 시스템을 테스트하여 버그와 결함을 발견하는 것이다.
그래서 Development Testing 어떻게 하냐?
Development Testing 단계에서는 주로 테스트 케이스를 많이 이용하여 Testing을 한다.
이런 Development Testing은 테스트 단위에 따라서 Unit Testing, Component Testing, System testing으로 나눌 수 있다.
Unit Testing은 개별 프로그램 단위나 객체, 클래스를 테스트한다.(Defection Testing에 해당)
그래서 Unit Testing에서는 객체와 관련된 operation을 테스트하고, attribute들을 막 설정하고 조회하고, 모든 상태에서 객체가 잘 작동하는지 확인한다.(Object class Testing)
그리고 Unit Testing은 단위가 작기 때문에 가능한 경우 자동화 되어서 실행/확인이 가능하다.(Automated Testing)
이 Automated Testing의 단계를 조금 더 살펴보자면 (ex. add(3,5) == 8케이스 사용)
- setup : 테스트 케이스, 즉 입력 및 예상 출력으로 먼저 초기화 // input : (3, 5), expected : 8
- call : 테스트할 객체 또는 메서드 호출 // result = add(3,5)
- assertion : 호출 결과를 예상 결과와 비교 // assertTrue(result == expected)
- tear-down : 리소스 해제 등 시스템 상태를 원래 상태로 복원 // 다른 테스트에 영향을 주지 않게 하기 위해서 이 단계를 많이 거치더라고요
다시 돌아와서, Unit Testing을 잘 하려면, 이미 작성해둔 메서드, 객체를 테스트 하는 것이기 때문에 결국 테스트 케이스를 잘 작성해야 한다.
이러한 Unit Testing 전략으로 Partitioning testing과 Guideline-based testing가 있다.
Partitioning testing은 어떤 전략인가요?
· 입력 그룹을 식별해서 파티션을 나누고
· 이 파티션에서 대표적인 값을 뽑고
· 모든 파티션에 대해서 testing 하는 전략이다
Guideline-based testing은 어떤 전략인가요?
· 테스트 가이드라인을 사용하여 테스트 케이스를 선택하는 것이다
· 테스트 가이드라인의 예시를 들어주세요!
o 보통 자주 저지르는 오류를 포함하는데
o ex) 자바 collection에서 처음, 중간, 마지막 요소를 테스트해보자
o 모든 오류 메시지를 생성해보자
o 입력이 overflow가 되도록 해보자
o 메서드 처리 결과가 너무 크거나 작도록 해보자
조금 더 큰 단위인 Component testing을 보자.
Component란 Unit test에서 다뤘던 그 Unit들을 통합하여 구성한 것이다.
그래서 유닛들을 통합했을 때 잘 작동하는지를 테스트 해야 한다.
component단위에서는 Component interface를 통해 객체가 작동하도록 하기 때문에
(사람으로 따지면 관절을 통해서 부위가 움직이잖아요!),
Component Interface가 명세에 따라서 잘 작동하는지 보이는 단계가 바로 Component Testing이다. (Interface가 핵심!!!)
그래서 이 단계에서는 Interface testing을 한다.
Interface testing의 목표는 Interface 오류나, Interface를 잘못 가정해서 생긴 defection을 찾는 것이다.
Interface 에는 어떤 것들이 있나요?
· Parameter Interface: 메서드나 프로시저에서 전달되는 데이터
o 객체 A를 전달해야하는데 객체B를 전달하면 안되겠죠?
· Shared memory Interface : 프로시저나 함수 간에 공유되는 메모리 블록
· Procedural Interface: 하위 시스템이 다른 하위시스템에 호출된 일련의 절차를 캡슐화. 이게 뭔말이냐?
o A가 B호출, B가 C를 호출, C가 D를 호출,,, 이런 과정, 절차를 말한다
o 이런 Procedural Interface error의 대표적인 예시가 OS에서 다루는 Deadlock
· Message passing interface : 하위 시스템이 다른 하위시스템으로부터 서비스 요청
Interface error에는 어떤 것이 있나요?
· Interface misuse : 인터페이스 사용 오류
o ex) 매개변수를 (피제수, 제수)로 보내야 하는데, (제수, 피제수)로 전달
· Interface misunderstanding : 호출 컴포넌트가 호출된 컴포넌트 동작에 대한 잘못된 가정을 포함
o ex) 회원 정보가 없으면 빈 회원 객체를 생성해서 반환해주는 줄 알았는데, null을 반환해주네?
· Timing error : 호출/호출된 컴포넌트간 다른 속도로 동작하고, 시간 정보에 접근이 이루어질 때 오류가 발생
o ex) 공유 데이터에 여러 객체가 동시에 접근해서 혼동이 생기는 경우
그러면 Interface error를 테스트 하기 위한 guideline을 알려주세요!
: 경계를 체크하거나, null 포인터를 매개변수로 보냈을 때 제대로 작동하는지 체크, 컴포넌트가 실패하도록 테스트를 설계해보고, 스트레스 테스트도 해보고, 공유 메모리 시스템에서 컴포넌트 활성화 순서도 바꿔 보고 등등
..
위에서 봤던 Component들이, 또는 시스템 일부가 서로 통합되어 새로운 시스템을 이루고 이걸 테스트 하는 것이 System Testing이다. 따라서 Component 간의 Interaction을 테스트하고, Interface를 통해서 제대로 작동하는지 테스트한다. (시스템 긴급동작도 테스트한다)
그래서 이 System Testing 단계에서는 시스템 간의 Interaction을 중점으로 보기 때문에, 이걸 Use-case로 개발하여 시스템테스트의 base로 사용한다(Use-case Testing)
여기서 System의 범위는 굉장히 넓어서, Reusable 시스템이나, 다른 하위 팀에서 개발한 컴포넌트들이 포함될 수가 있다. 여태 개발한 것들을 모아서 테스트한다고 보면 된다.
그리고 System 자체가 광범위 하기 때문에 “어느 정도 까지 테스트하면 된다”. 즉 Coverage를 정의 해야 한다. (System Testing Policy). 원자로 시스템, 항공 시스템의 경우에는 더 엄격한 Testing Policy가 필요하겠죠?
여기 까지가 Development Testing이고,
이제 개발을 끝냈으면 Release를 해야 하는데, 그 전에 Release testing을 해야 합니다.
(개발 팀 외부에서 사용하도록 의도된 특정 릴리즈 시스템을 유저에게 제공하기 전에 테스트하는 것이다.)
왜 Release Testing을 하나요?
시스템 공급자에게 시스템이 충분히 좋다는 것을 확신시켜주고, 기능, 성능에 대한 신뢰성을 제공하고, 정상 사용중에 실패하지않음을 보여주기 위함입니다!
Release Testing도 결국 시스템을 테스팅 하는 것 아니에요?
맞습니다. 하지만 시스템 테스팅은 시스템 내 error를 발견하는데 중점을 두지만, Release Testing은 조금 더 시스템Provider 입장에서, 시스템이 요구사항을 충족하고 외부 사용에 충분히 좋은지를 확인시켜주는 테스트 합니다
위에서 말한 것처럼, 시스템 요구사항을 만족하고 충분히 좋은지를 알려줘야 합니다.
그래서 크게 보면 아래 두 가지 테스트를 진행합니다
Requirement based Testing : 요구사항을 검토하고, 이에 대한 테스트를 개발합니다. 보통 시나리오를 가지고 테스트를 합니다
Performance Testing : 성능/안정성과 같은 System attribute 테스트를 합니다. 시스템이 충분히 외부에서 사용될 수 있음을알려주는 것이죠!(ex. stress test)
이제 Release 준비가 끝났다면, 사용자에게 Release를 뿌려봐야겠죠?
하지만 Release한다고 해서 Testing이 끝난 것이 아닙니다.
사용자의 작업 환경에서 발생하는 영향들이 시스템의 신뢰성, 사용성에 영향을 주기 때문에 User testing을 반드시 해야 합니다.
이 User testing에서는 사용자, 또는 잠재적 사용자가 자신의 환경에서 시스템을 테스트 하고, 의견을 제공합니다.
User testing의 유형에는 크게 3가지가 있습니다
· Alpha testing : 소프트웨어 사용자가 개발팀과 함께 소프트웨어를 테스트합니다
o 게임 유저를 회사에 초청해서 테스트 하거나, 사내 테스트를 하는 등
· Beta testing : 테스트를 위한 릴리즈를 사용자에게 뿌려서 문제를 발견하고 피드백을 받습니다.
· Acceptance testing : 요거는 살짝 결이 다른데, 고객이 시스템을 테스트 하고, 고객 환경에서 시스템을 사용할 준비가되었는지 평가, 결정합니다. (주로 외주를 하고 Product를 제공하는 맞춤형 시스템에서 많이 하는 것)
o 특정 경우 애자일과 안맞을 수도 있다(계약맺고 개발하는 것을 생각해봐요)
지금까지 다룬 Testing은 작성된 코드를 바탕으로 테스트를 작성했지만,
이와 반대로 테스트를 작성한 후 코드를 작성하는 방식이 있다.
이를 TDD(Test-Driven Development) 라고 한다. TDD는 테스트와 코드 개발을 교차진행하는 방식이다. 테스트 통과가 주요 동인이고, 단계에 맞는 테스트를 개발하고 코드를 점진적으로 개발해 나간다.
어떤 장점이 있기에 TDD를 사용할까?
· Regression testing에도 효과적이다. (변경사항 이전에 작동하던 코드가 깨지는지)
· Simplified Debugging (문제가 있는 곳을 찾기 수월함)
· System documentation(테스트 케이스가 명세의 역활을 한다)
· Code coverage가 올라간다.
o Code Coverage 종류로는 Statement/Branch/Condition Coverage가 있다
o 코드 커버리지를 올리려면
§ setup 부분과 call 부분을 신중하게 설계
§ public이 private을 반드시 호출
§ 모듈화를 잘해서 테스트 케이스를 쉽게
o 물론 Code coverage만으로는 테스트 스윗 평가에 충분하지 않다.
§ Mutation(변형) testing을 해보자 (코드 변형 후 테스트가 결함 감지할 수 있는지 확인하는 테스팅)
'소프트웨어 공학 > 시험 공부 정리' 카테고리의 다른 글
[소공 시험공부] Software Reuse (0) | 2024.06.07 |
---|---|
[소공 시험공부] Safety Engineering (0) | 2024.06.06 |
[소공 시험공부] Software Reliability (0) | 2024.06.06 |
[소공 시험공부] System Dependability (0) | 2024.06.06 |
[소공 시험공부] Software Evolution (0) | 2024.06.06 |