SW 개발 일반/레거시코드와 놀기

느리지만 그나마 쉬운 테스트 개발하기

growdai1y 2025. 1. 20. 14:12

임베디드 시스템을 개발하는 환경에서 테스트는 종종 골칫거리로 여겨집니다. 특히 레거시 코드가 많이 쌓여 있는 경우에는 더욱 그렇습니다. 하지만 이런 상황에서도 기능 수준에서 동작을 확인할 수 있는 방법이 있습니다. 이번 글에서는 임베디드 시스템의 C++ 코드를 직접 다루지 않고도 외부에서 Python을 사용해 기능 테스트를 수행하는 방식을 소개하겠습니다. 또한 이 과정에서 Cucumber를 활용해 쉽고 읽기 좋은 테스트 코드를 작성하는 방법도 다룹니다.

기능 테스트를 위한 Cucumber 프레임워크
기능 테스트를 위한 Cucumber 프레임워크


왜 Python을 사용하는가?

Python은 단순함과 강력한 라이브러리 생태계 덕분에 테스트 자동화에 매우 적합한 언어입니다. C++로 작성된 임베디드 시스템의 테스트 코드를 직접 작성하려면 복잡한 빌드 환경과 코드 수정이 필요할 수 있지만, Python을 사용하면 이런 부담을 줄일 수 있습니다. Python은 SSH를 통한 원격 연결, 테스트 데이터 생성, 결과 분석 등 다양한 작업을 간단히 처리할 수 있습니다.


외부에서 기능 테스트를 수행하기 위한 준비

1. 임베디드 시스템과의 인터페이스 확인

임베디드 시스템과 외부 테스트 환경이 원활히 상호작용하려면 다음 요소들이 필요합니다:

  • 네트워크 연결: SSH로 접근 가능해야 합니다.
  • 테스트 실행 인터페이스: 시스템에서 실행할 수 있는 테스트 스크립트나 명령어가 있어야 합니다.
  • 결과 출력 방식: 테스트 결과를 파일, 로그, 또는 표준 출력(stdout) 형태로 확인할 수 있어야 합니다.

2. Python과 SSH를 활용한 테스트 실행

Python에서는 paramiko와 같은 라이브러리를 사용하여 SSH를 통해 임베디드 시스템에 접근할 수 있습니다. 테스트 프로세스는 다음과 같습니다:

  1. Python 스크립트로 SSH 연결을 설정합니다.
  2. 임베디드 시스템에 테스트를 실행할 Python 스크립트를 업로드합니다.
  3. 업로드된 스크립트를 실행하고 결과를 수집합니다.

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) 테스트가 실패한 경우, 실패 원인과 관련된 로그가 출력됩니다. 이를 통해 문제를 디버깅할 수 있습니다.


테스트의 강점

이 접근 방식은 다음과 같은 장점이 있습니다:

  1. 레거시 코드 수정 최소화: 기존 임베디드 시스템 코드를 변경할 필요 없이 외부에서 동작을 확인할 수 있습니다.
  2. 가독성: Cucumber의 BDD 스타일을 통해 테스트 의도를 쉽게 전달할 수 있습니다.
  3. 재사용 가능성: 테스트 스크립트를 다른 시스템이나 상황에서도 재활용할 수 있습니다.
  4. 유연성: Python의 다양한 라이브러리를 활용하여 테스트를 확장할 수 있습니다.

결론

임베디드 시스템에서의 테스트는 어렵지만, Python과 Cucumber를 활용하면 상대적으로 쉽게 접근할 수 있습니다. 이 방법은 레거시 코드의 한계를 극복하면서도 기능 수준에서 시스템의 동작을 확인할 수 있는 강력한 도구가 될 것입니다. 테스트는 느릴 수 있지만, 그나마 쉽고 유지보수 가능한 방향으로 테스트를 시작할 수 있습니다. (다만 슬프게도 결국 단위 테스트는 필요합니다.)

 

매일 성장하기

반응형