2. Why?
IoT의 특성 = 하드웨어 + 소프트웨어 + 네트워크 …
실환경에서의 통합 테스트가 중요하다. 그럼에도 불구하고
소프트웨어 단위테스트를 보려는 이유는
- 테스트 비용이 비싸므로
- 소프트웨어 디버깅이 쉬우므로
- 테스트 시점을 앞당기기 위해
- 특정 상황(환경)을 임의로 제공해 주기 쉬우므로
- 거기다 만약 소프트웨어 로직이 복잡하다면.
4. 단위 테스트 개요
- 목적 : 통합테스트에 앞서 시스템의 개별단위에 대해 결함을 찾고 위험을
감소시킴
- 단위 : 독립된 가장 작은 단위의 테스트 가능한 아이템 (Class, function, 화면
등)
- 수행주체 : 개발자, 일부 경우 별도 테스트 인력
단위테스트
통합테스트
통합과 단위의 차이V모델에서의 단위테스트
5. ※ 단위 테스트 vs 상위레벨 테스트
- 일반적으로 상위 테스트(통합, 시스템 테스트 등)에 비해 단위테스트는 테스트하기가 더 쉽다.
- 각 테스트의 목적이 다르며, 통합 테스트에서는 단위테스트에서 하려는 테스트를 못하는 경우가
많다(테스트 커버리지를 높이기 어렵다)
- 상위 테스트 이전인 단위테스트를 잘 수행하면 품질비용(결함 발견, 수정 비용 등)을 절감할 수 있다
- 단위테스트는 개발을 더 잘, 더 빠르게 할 수 있도록 돕는다
- 결함 발생시 특정 단위 모듈의 문제인지 아니면 다른 영역의 문제인지 쉽게 파악할 수 있다.
- 단위테스트는 자동화하기 쉬우며, 이렇게 자동화된 테스트는 수정 후 재테스트를 용이하게
만든다
6. IoT 및 과제 간략 소개
IoT (Internet Of Things(Everything))
- 1999년에 P&G 의 케빈 애쉬튼이 “RFID 및 기타 센서를 일상생활 속 사물에 탑재함으로써 사물
인터넷이 구축될 것”이라고 언급하며 최초로 사용
- 05년 국제전기통신연합(ITU)은 처음으로 사물 인터넷 관련 보고서를 발간해 사물 인터넷의 개념을
정립하고 관련 기술과 발전 방향을 제시
IoT에서의 테스트?
임베디드의 특성, 내/외부 네트워크 성능, 보안, 다양한 단말에 따른 사용자 관점의 흐름(Smartness),
하드웨어와 소프트웨어 간의 아키텍처(주로 설정부분) 취약성, 소프트웨어와 전체 시스템의 복잡도,
디바이스와 합쳐지면서 엄청난 양의 코드, 더 짧아진 개발기간, 메모리, 전력, 밴드위쓰, 배터리 수명
등과 같은 리소스 고려 등의 테스트 고민이 필요하다
(http://www.logigear.com/magazine/issue/past-articles/testing-strategy-for-the-iot/)
7. 프로젝트 간략 소개
-Smart Factory의 한 내용으로 운영 장비에 저렴한 센서 장비와 이를 활용한
어플리케이션을
구축하는 과제
*OHT: Overhead Hoist Transfer
생산중인 반도체들을 옮기는 장비
- 장비 비쌈,
- 반도체 비쌈,
- 멈추면 비쌈 (** 다 비쌈 **)
유사한 도메인으로 이해해 보기
칫솔로 대체해 보면?
. 칫솔 : 식후 3,3,3
. 목표 : 사용자의 칫솔질 패턴을 파악하여 치과 진료에 활용한다
(1) 사용자의 하루 식후 양치 횟수 파악
(2) 사용자의 칫솔질 패턴을 분석
- 너무 세게(빠르게)하지 않는지, 위아래, 좌우로 꼼꼼하게 하는지
(3) 칫솔의 사용 정도에 따른 교체 주기 알림
Eclipse Kura Framework을 이용한 구현
8. 개발 아키텍처 및 단위 테스트 대상
- 하드웨어, 관련 프레임워크와 단위 모듈과의 관계
콘트롤러
. openPort (~)
. run
. closePort
Raspberry Pi
자세제어
센서
카메라
IoT 지원 개발 프레임워크
(Eclipse Kura Framework)
(port)
/dev/ttyUSB0
<테스트 대상>
…
<테스트 대상>
…
< 테스트 대상>
…
CommConnection
(port)
/dev/ttyUSB1
<org.eclipse.kura.comm>
CommConnection
…
[Example ]
단위모듈
1) 보드가 켜지면 Kura Framework는 콘트롤러를 구동한다
2) 콘트롤러는 원하는 센서 장비와 연결한다
3) 콘트롤러는 각 단위 모듈들을 호출하고 각 모듈과 해당 모듈이 사용하는
센서 연결을 관리한다
4) 각 단위 모듈은 프로그래밍된 로직을 수행한다
…
9. 단위 테스트 필요성 및 가상화 전략
- 개발한 단위 모듈의 다양한 로직 테스트를 위해 특정 상황을 쉽게 만들 필요가 있음
- 통합된 상태에서는 하드웨어의 특정 상태, 이상 동작 등을 임의로 만들기가 어려워 센서,
프레임워크 동작을 가상으로 만들고, 다양한 테스트를 할 필요가 있음
테스트 A
<테스트 대상>
…
<테스트 대상>
…
< 테스트 대상>
…
MockConnection
<org.eclipse.kura.comm>
테스트 B
테스트 C
MockConnection
…
MockConnection
…
FAKEDSensor
테스트 모드:
. 정상1
. 정상2
. 에러
. 오류 …
1) 모의 객체 주입
2) 테스트 대상 클래스, 메소드 호출
3) 테스트 수행 후 리턴 값, 실제 수행 값 검증
프레임워크 대체센서, 보드 대체
10. ※ 단위테스트를 돕는 가상객체 - Mock, Stub, Fake오브젝트 란?
From xunitpattern, Martin Fowler about Mock and Stub
. Mock : 테스트 대상이 참조하는 오브젝트와 동일한 인터페이스를 구현한 가상 객체. 기
대동작과 함께 사전에 프로그래밍되어 테스트 시점에 기대결과를 만족하는지 확인할 수
있다
. Stub : 테스트 대상의 요청에 대해 응답하도록 구현된 오브젝트. 몇 개의 기본적인 요청
에 대해 응답할 수 있다 (예를 들면, 이메일 게이트웨이 스텁은 메시지가 보내졌다는 정
보 정도를 제공한다)
. Fake: 실제 오브젝트와 유사하게 실제 동작하는 오브젝트. 하지만 실제 오브젝트보다는
경량화되어 있고, 실제 동작과는 다르다
Mockito 와 PowerMock 소개
- Mockito (http://site.mockito.org/ )
: 테스트 대상이 참조하는 객체들의 동작을 런타임에 임의로 조작하고,
테스트 대상의 수행 결과를 확인하도록 지원하는 툴
- PowerMock (https://code.google.com/p/powermock/ )
: static, private 변수 등을 대체(낚아채기?)하기 위한 프레임워크
11. 단위테스트 샘플 소개
(1) StopStateAnalyze
- 자세방위 센서 정보로부터 정지상태 여부를 판단하는기능
- Mock 미사용
- 입력으로 받은 X,Y,Z축 기울기 성분, 가속도 성분 등의 다양한 센서 값으로부터 정지여부
정상 판단 여부
(2) AHRSSensorSetting
- 보드 부팅 시 자세방위 센서 초기 설정을 수행하고, 센서 이상을 탐지하는 기능
- Mockito 사용 (센서 응답 값을 임의로 조작)
- 센서에 의도한 설정 커맨드가 정상 전송되는지, 센서의 다양한 상황에 대해 의도한 동작을
하는지 테스트
(3) TurnStateAnalyze
- 사전에 메모리 DB에 저장된 자세방위 센서 값 raw 데이터를 읽어 운전상태(좌회전, 우회전
등)를 분석하고 다시 저장하는 기능
- Mockito+PowerMock 사용
- 사전에 시뮬레이팅 된 센서 값을 저장해 놓고, 이 데이터를 정상 분석하여 적합한
운전상태 값을 저장했는지 확인하는 테스트
12. 1. 순수 Junit 테스트 코드
- StopStateAnalyzer 테스트 대상 분석 -
(Logic) 정지상태 판단
(1) X,Y,Z 축 기울기(roll,pitch,yaw) 증감이 오차범위 이내이고,
(2) X,Y,Z 축 가속도 증감이 오차 범위 이내이며.
(3) (1),(2) 상태가 15초(측정 값 500회) 이상 지속될 때
- 테스트 조건 -
(a) 기본– 정지 / 이동 상태
(b) 기울기 조건
(c) 가속도 조건
(d) 측정 횟수 500회 경계 조건
- 단위 테스트 -
UT_01~02) 기본조건 – (1),(2),(3)을 모두 만족/불만족한 상태의 결과 값 확인
UT_03~06) X,Y,Z축 기울기 값 중 1개의 성분이 오차범위 이상일 때, X,Y,Z 축 모두 오차범위
이상일 때
UT_07~10) X,Y,Z 축 가속도 성분이 오차 범위 이상일 때
UT_11~13) 정지상태 지속이 500회, 501회 일 때
13. 개발코드개발코드개발코드개발코드 분석분석분석분석
---- 미공개미공개미공개미공개 ----
StopStateAnalyzer
(로직) 기울기 값이 2 이상, 가속도 값이 0.1 이상 변동
이 1개라도 있는 경우 OHT는 이동 중으로 파악
( 코드 검토 의견 )
변수(별도 상수화) 처리
필요
(로직) 정지 횟수가 500회를 초과(501회부
터)하는 경우 OHT가 정지했다고 판단함
18. StopStateAnalyzer
테스트 코드, 기본적인 테스트 5
501번째 정지 상태로 분석된 후 동작 확
인하기 위해 502회 등을 확인한다
기대결과 : 502회 부터는 다시 리셋되어
처음부터 다시 카운팅을 한다
결함: static 변수 stoppedTime이 리셋되지
않아 계속 정지 상태로 값을 반환한다
19. 2. Mockito를 이용한 테스트 코드
- AHRSSensorSetting 테스트 대상 분석 -
(Logic) 보드 부팅시 자세제어 센서 설정을 수행하고, 센서 이상을 탐지하는 기능
(1) 각 센서 값 초기화(0)
(2) 센서 값 출력 주기 설정
(3) 그 외 값은 디폴트 값 사용
(4) (1),(2),(3) 모두 정상 수행 후 센서 응답(ok/er)을
확인하여 최종적으로 정상 설정 / 이상 발생 여부를 반환
- 테스트 조건 -
(a) 기본– 정상설정
(b) 센서 이상 응답
(c) 센서 연결 불량
- 단위 테스트 -
UT_01) 기본조건 – 센서 값 설정(커맨드 수행) 후 센서의 응답 값이 모두 ok 로 정상 설정
반환 확인
UT_02~04) 커맨드 수행 후 센서 응답 값이 오류(er)일 때 이상 발생 반환을 확인(관련 동작
확인)
UT_05) 아예 연결 실패로 RuntimeException이 발생할 때의 동작 확인
20. 개발코드개발코드개발코드개발코드 분석분석분석분석
---- 미공개미공개미공개미공개 ----
AHRSSensorSetting
개발 코드, Mocking이 필요한 부분 파악
센서와 연결.
(코드 리뷰) 연결 실패시(IOException) 에
대한 처리 없음
- 데이터 출력 주기, 출력 값 선택 등
기본 설정,
- 자세 센서 각 측정 값에 대해 현재 값을
0으로 설정
- 센서가 er 코드를 보내는 경우 3초 후 재시도, 최대
3회까지 시도 후 다음 커맨드 수행
- 3회까지도 실패한 경우 시스템 알림 처리하고 그
다음 스텝 계속 수행
22. AHRSSensorSetting
테스트 코드, setUp에서 각 자원들을 가상 객체로 생성하는 부분
FakedAHRSFakedAHRSFakedAHRSFakedAHRS
1) 테스트 모드 입력
2) 입력 요청 값 store
3) 테스트 모드에 따른 출력 또는
Exception 발생
테스트 수행을 위한 Fake Object 구현
23. AHRSSensorSetting
테스트 코드, 기본 테스트에서 각 가상 객체들의 기대 동작을 정의하고,
테스트를 하고, 결과를 확인하는 코드
테스트 목적에 따라
가상 객체에 사전에 정의한 역할을
설정 = 테스트모드:정상
Mockito가 제공하는 기능을 이용해
가상 객체들에게 특정 상황(when)에
수행 내용(then~)을 정의 = 레코딩
테스트 수행
가상 객체에 테스트 수행 후 결과
를 확인
24. AHRSSensorSetting
테스트 목적에 따라
가상 객체에 사전에 정의한 역할을
설정 = 테스트모드:에러
결함: 센서가 er 코드를 최종적으로 보내는 경우
업무적으로는 이후 동작이 의미가 없으나, 그대
로 이후 동작을 진행 시킨다
테스트 코드, 오류코드 반환시 동작확인 테스트
25. AHRSSensorSetting
테스트 목적에 따라
가상 객체에 사전에 정의한 역할을
설정 = 테스트모드:연결오류
결함: 센서 연결 실패로 Exception이 발생해도
로그만 찍고 이후 동작을 진행 시킨다
테스트 코드, 센서 연결 실패 시 동작확인 테스트
26. 3. PowerMock, Mockito를 이용한 테스트 코드
- TurnStateAnalyzer 테스트 대상 분석 -
사전에 메모리 DB에 저장된 자세방위 센서 값 raw 데이터를 읽어
운전상태-회전성분을 분석하고 다시 저장하는 기능
- 테스트 조건 -
(a) 회전없음 경계조건
(b) 좌회전 경계조건
(c) 우회전 경계조건
(d) 형식이 잘못된 데이터
- 단위 테스트 -
UT_01~02) 직진으로 판단하는 경계조건
UT_03~04) 좌회전으로 판단하는 경계조건
UT_05~06) 좌회전으로 판단하는 경계조건
UT_07~08) – 발생 가능성이 낮다고 생각하여 작성 안 함 -
29. TurnStateAnalyzer
테스트 코드, PowerMock 사용을 위한 사전 준비
내부 static 멤버 변수를 동적으로 대체하기 위한
PowerMock 구문 사용. Whitebox.setInternalState
개발된 로직에 따라 사전에 테스트용 데이터를
저장 = 회전하지 않는 데이터
테스트 수행 및 수행 결과를 다시 DB에서
조회 <= 현재 개발코드가 미구현
테스트 코드, 사전 데이터 설정
30. ※ 테스트가 용이한 개발하기 – Dependency Injection
- 의존성 주입, Dependency Injection
: 개발 클래스가 사용하는 타 클래스를 클래스 내부에서 생성하는게 아니라
외부에서 생성해서 세팅하도록 하는 기법
- 장점
: 단위테스트 수행 등 원하는 시점에 따라 다른 의존성을 주입할 수 있다
: 테스트에서뿐만 아니라 개발 관점에서도 유연한 설계가 된다 (인터페이스로 입력을 받고,
이 구현체는 나중에 다양하게 변경 가능)
- 의존성 주입방법 2가지
간단한 의존성 주입방법은
: 생성자에서 의존 관계의 클래스를 입력 받아 설정하기
: 별도의 set/get 메소드를 통해 그때그때 변경 가능하게 하기
31. 수행후기
- IoT에서 제일 중요한 건 현장 테스트
하드웨어+소프트웨어+네트워크+현장상황(수많은 변수들)
- 하지만, 실환경 접근(반도체 생산 공장)이 제한적이고, 테스트 상황을 연출하기 어려워
고민한 테스트 전략
- 개발 당사자가 아닌 3자가 단위테스트를 접근하는 건 무척 어려움
(개발 코드 분석, 잦은 코드 변경 등)
- Kura Framework이 지원해주는 단위테스트 환경이 없어서 많은 Mock 작업이 필요했음
- 반면에, 테스트가 용이한 개발이 아쉽기도 (모듈화, 의존성 주입 형태)
- 작성한 가상 객체 자체에 결함이 있을 수 있거나, 가상 객체가 실제 동작과 다르게
동작할 수도 있음
활용방안
- IoT가 단위테스트하기 가장 어려운 도메인, 보통 많이 사용되는 다양한 프레임워크들은
자체적으로 다양하고 편리한 단위 테스트 환경, 유틸들을 제공하므로 쉽게 활용 가능
(ex1) Spring Framework Test Utils : 서버를 띄우지 않아도, 클라이언트 Request가 없어도
(ex2) SparkContext : 로컬 PC에서, 대용량 저장소없이, 소프트웨어 레벨에서 그때그때
데이터를 변경해 가며 테스트 가능
32. 단위테스트 팁
(1) 개발 코드 자체를 테스트가 용이하도록 개발하라 (의존성 주입 같은 패턴 활용)
(2) 테스트 코드 작성 우선순위를 고려하라
- 시간이 없는 경우 복잡한 로직이 있는 클래스부터 접근
- 원하는 테스트를 하기 어렵거나 시간이 오래 걸리는 테스트에 대한 접근
- 테스트 커버리지를 측정해 보라
(내가 개발한 코드의 어디가 테스트되고, 어디가 테스트되지 않았는지를 눈으로 보고
고민해 보라)