임베디드 시스템을 개발하는 환경에서 테스트는 종종 골칫거리로 여겨집니다. 특히 레거시 코드가 많이 쌓여 있는 경우에는 더욱 그렇습니다. 하지만 이런 상황에서도 기능 수준에서 동작을 확인할 수 있는 방법이 있습니다. 이번 글에서는 임베디드 시스템의 C++ 코드를 직접 다루지 않고도 외부에서 Python을 사용해 기능 테스트를 수행하는 방식을 소개하겠습니다. 또한 이 과정에서 Cucumber를 활용해 쉽고 읽기 좋은 테스트 코드를 작성하는 방법도 다룹니다.
왜 Python을 사용하는가?
Python은 단순함과 강력한 라이브러리 생태계 덕분에 테스트 자동화에 매우 적합한 언어입니다. C++로 작성된 임베디드 시스템의 테스트 코드를 직접 작성하려면 복잡한 빌드 환경과 코드 수정이 필요할 수 있지만, Python을 사용하면 이런 부담을 줄일 수 있습니다. Python은 SSH를 통한 원격 연결, 테스트 데이터 생성, 결과 분석 등 다양한 작업을 간단히 처리할 수 있습니다.
외부에서 기능 테스트를 수행하기 위한 준비
1. 임베디드 시스템과의 인터페이스 확인
임베디드 시스템과 외부 테스트 환경이 원활히 상호작용하려면 다음 요소들이 필요합니다:
- 네트워크 연결: SSH로 접근 가능해야 합니다.
- 테스트 실행 인터페이스: 시스템에서 실행할 수 있는 테스트 스크립트나 명령어가 있어야 합니다.
- 결과 출력 방식: 테스트 결과를 파일, 로그, 또는 표준 출력(stdout) 형태로 확인할 수 있어야 합니다.
2. Python과 SSH를 활용한 테스트 실행
Python에서는 paramiko와 같은 라이브러리를 사용하여 SSH를 통해 임베디드 시스템에 접근할 수 있습니다. 테스트 프로세스는 다음과 같습니다:
- Python 스크립트로 SSH 연결을 설정합니다.
- 임베디드 시스템에 테스트를 실행할 Python 스크립트를 업로드합니다.
- 업로드된 스크립트를 실행하고 결과를 수집합니다.
3. Cucumber로 시나리오 기반 테스트 작성
Cucumber는 비기술적인 사람도 이해할 수 있는 BDD(Behavior-Driven Development) 스타일로 테스트를 작성할 수 있게 도와줍니다. 테스트는 주로 다음과 같은 구조로 작성됩니다:
- Feature 파일: 테스트 시나리오를 정의합니다.
- Step Definitions: 각 시나리오의 단계를 실제 코드로 구현합니다.
예를 들어, 임베디드 시스템의 특정 기능을 테스트하는 경우:
Feature 파일 예시
Feature: 임베디드 시스템 기능 테스트
Scenario: 시스템이 정상적으로 온도를 측정한다
Given 시스템이 초기화되었다
When 온도 센서 데이터를 요청한다
Then 정상 범위의 온도 값이 반환된다
Step Definitions 예시 (Python)
from behave import given, when, then
import paramiko
@given('시스템이 초기화되었다')
def step_initialize_system(context):
# SSH 연결 및 초기화 명령 실행
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('embedded-system-ip', username='user', password='pass')
stdin, stdout, stderr = client.exec_command('initialize_system')
context.client = client
assert "Success" in stdout.read().decode()
@when('온도 센서 데이터를 요청한다')
def step_request_temperature_data(context):
stdin, stdout, stderr = context.client.exec_command('get_temperature')
context.temperature_data = stdout.read().decode()
@then('정상 범위의 온도 값이 반환된다')
def step_validate_temperature(context):
temperature = float(context.temperature_data)
assert 15.0 <= temperature <= 30.0, "온도 값이 정상 범위를 벗어났습니다."
4. 테스트 실행 및 결과 확인
테스트를 실제로 실행하고 결과를 확인하려면 아래 단계를 따릅니다:
(1) Python 스크립트를 작성한 후 behave 명령어를 사용하여 테스트를 실행합니다.
behave features/embedded_system_test.feature
(2) 테스트 결과는 터미널에 출력되며, 성공 여부를 명확히 보여줍니다.
Feature: 임베디드 시스템 기능 테스트
Scenario: 시스템이 정상적으로 온도를 측정한다
Given 시스템이 초기화되었다 # PASSED
When 온도 센서 데이터를 요청한다 # PASSED
Then 정상 범위의 온도 값이 반환된다 # PASSED
1 feature passed, 0 failed
1 scenario passed, 0 failed
3 steps passed, 0 failed
(3) 테스트가 실패한 경우, 실패 원인과 관련된 로그가 출력됩니다. 이를 통해 문제를 디버깅할 수 있습니다.
테스트의 강점
이 접근 방식은 다음과 같은 장점이 있습니다:
- 레거시 코드 수정 최소화: 기존 임베디드 시스템 코드를 변경할 필요 없이 외부에서 동작을 확인할 수 있습니다.
- 가독성: Cucumber의 BDD 스타일을 통해 테스트 의도를 쉽게 전달할 수 있습니다.
- 재사용 가능성: 테스트 스크립트를 다른 시스템이나 상황에서도 재활용할 수 있습니다.
- 유연성: Python의 다양한 라이브러리를 활용하여 테스트를 확장할 수 있습니다.
결론
임베디드 시스템에서의 테스트는 어렵지만, Python과 Cucumber를 활용하면 상대적으로 쉽게 접근할 수 있습니다. 이 방법은 레거시 코드의 한계를 극복하면서도 기능 수준에서 시스템의 동작을 확인할 수 있는 강력한 도구가 될 것입니다. 테스트는 느릴 수 있지만, 그나마 쉽고 유지보수 가능한 방향으로 테스트를 시작할 수 있습니다. (다만 슬프게도 결국 단위 테스트는 필요합니다.)
'SW 개발 일반 > 레거시코드와 놀기' 카테고리의 다른 글
레거시 코드와 놀기: 호출 추출과 재정의 (Extract and Override Call) (0) | 2025.01.24 |
---|---|
레거시 코드와 놀기: 정적 메소드 드러내기 (Expose Static Method) (0) | 2025.01.22 |
레거시 코드와 놀기: 전역 참조 캡슐화 (Encapsulate Global Reference) (0) | 2025.01.20 |
레거시 코드와 놀기: 메소드 객체 추출 (Breaking Out Method Object) (0) | 2025.01.19 |
레거시 코드와 놀기: 매개변수 적응 기법 (Adapt Parameter) (0) | 2025.01.17 |