[unit-testing] Arduino 코드를 단위 테스트하려면 어떻게해야합니까?

Arduino 코드를 단위 테스트 할 수 있기를 원합니다. 이상적으로는 코드를 Arduino에 업로드하지 않고도 테스트를 실행할 수 있습니다. 어떤 도구 나 라이브러리가 도움이 될 수 있습니까?

거기입니다 개발에 아두 이노 에뮬레이터 유용 할 수 있지만, 아직 사용할 준비가 될 것 같지 않습니다.

Atmel의 AVR Studio 에는 유용한 칩 시뮬레이터가 포함되어 있지만 Arduino IDE와 함께 사용하는 방법을 알 수 없습니다.



답변

Arduino 장치 또는 에뮬레이터에서 장치 테스트를 실행하지 마십시오

마이크로 컨트롤러 Device / Emulator / Sim 기반 테스트 사례

단위 테스트가 의미하는 바에 대해 많은 토론이 있으며 실제로 그것에 대해 논쟁하려고하지는 않습니다. 이 게시물에서는 궁극적 인 대상 하드웨어에 대한 모든 실제 테스트
를 피하도록 지시하지 않습니다 . 가장 평범하고 빈번한 테스트에서 대상 하드웨어를 제거하여 개발 피드백주기를 최적화하는 데 중점을두고 있습니다. 테스트중인 단위는 전체 프로젝트보다 훨씬 작은 것으로 가정합니다.

단위 테스트의 목적은 코드의 품질을 테스트하는 것입니다. 단위 테스트는 일반적으로 통제 범위 밖에서 요인의 기능을 테스트하지 않아야합니다.

Arduino 라이브러리, 마이크로 컨트롤러 하드웨어 또는 에뮬레이터의 기능을 테스트하더라도 이러한 테스트 결과가 자신의 작업 품질에 대한 정보를 제공하는 것은 불가능 합니다. 따라서 대상 장치 (또는 에뮬레이터)에서 실행되지 않는 단위 테스트를 작성하는 것이 훨씬 더 가치 있고 효율적입니다.

대상 하드웨어에 대한 빈번한 테스트로 인해주기가 매우 느립니다.

  1. 코드 조정
  2. 컴파일 및 Arduino 장치에 업로드
  3. 행동을 관찰하고 있는지 추측 당신의 코드는 당신이 무엇을 기대하고있다
  4. 반복

직렬 포트를 통해 진단 메시지를받을 것으로 예상되지만 프로젝트 자체에서 Arduino의 유일한 하드웨어 직렬 포트를 사용해야하는 경우 3 단계는 특히 불쾌합니다. SoftwareSerial 라이브러리가 도움이 될 것이라고 생각한 경우, 그렇게하면 다른 신호를 동시에 생성하는 것과 같은 정확한 타이밍이 필요한 기능이 중단 될 수 있음을 알아야합니다. 이 문제는 나에게 일어났다.

다시, 에뮬레이터를 사용하여 스케치를 테스트하고 실제 Arduino에 업로드 할 때까지 시간이 중요한 루틴이 완벽하게 실행 된 경우, 배울 유일한 교훈은 에뮬레이터에 결함이 있다는 것입니다. 자신의 작업 품질에 대해서는 아무 것도 나타내지 않습니다 .

장치 또는 에뮬레이터에서 테스트하기가 어리 석다면 어떻게 해야 합니까?

컴퓨터를 사용하여 Arduino 프로젝트에서 작업하고있을 것입니다. 그 컴퓨터는 마이크로 컨트롤러보다 훨씬 빠릅니다. 컴퓨터 에서 빌드하고 실행 하기위한 테스트를 작성하십시오 .

Arduino 라이브러리와 마이크로 컨트롤러의 동작은 정확하거나 적어도 일관되게 부정확 한 것으로 가정 해야합니다 .

테스트 결과가 예상과 달리 출력을 생성하면 테스트 된 코드에 결함이있을 수 있습니다. 테스트 결과가 예상과 일치하지만 Arduino에 업로드 할 때 프로그램이 올바르게 작동하지 않으면 테스트가 잘못된 가정에 기초한 것이며 결함이있는 테스트 일 수 있습니다. 두 경우 모두 다음 코드 변경 내용에 대한 실질적인 통찰력을 얻게됩니다. 피드백의 품질이 ” 무슨 문제 가 있음”에서 “이 특정 코드 가 깨졌습니다”로 향상되었습니다 .

PC에서 테스트를 빌드하고 실행하는 방법

가장 먼저해야 할 일은 테스트 목표를 파악하는 것 입니다. 테스트하려는 자체 코드 부분을 ​​생각한 다음 테스트를 위해 별도의 부분분리 할 수있는 방식으로 프로그램을 구성하십시오 .

테스트하려는 부품이 Arduino 기능을 호출하는 경우 테스트 프로그램에서 모형 대체품을 제공해야합니다. 이것은 생각보다 훨씬 적은 작업입니다. 실물 모형은 실제로 테스트를 위해 예측 가능한 입력 및 출력을 제공하는 것 외에는 아무것도 할 필요가 없습니다.

테스트하려는 자체 코드는 .pde 스케치 이외의 소스 파일에 존재해야합니다. 걱정하지 마십시오. 스케치 외부에서 소스 코드를 사용해도 스케치가 컴파일됩니다. 실제로 내려 가면 스케치 파일에서 프로그램의 일반적인 진입 점보다 조금만 정의해야합니다.

남아있는 것은 실제 테스트를 작성하고 좋아하는 C ++ 컴파일러를 사용하여 컴파일하는 것입니다! 이것은 실제 사례를 통해 가장 잘 설명 될 수 있습니다.

실제 작업 예

여기에있는 애완 동물 프로젝트 중 하나 는 PC에서 실행되는 간단한 테스트가 있습니다. 이 답변 제출을 위해 Arduino 라이브러리 함수 중 일부를 모의 한 방법과 해당 모의를 테스트하기 위해 작성한 테스트를 살펴 보겠습니다. 내가 목업을 쓴 사람이기 때문에 다른 사람들의 코드를 테스트하지 않는다는 것에 대해 이전에 말한 것과 반대되는 것은 아닙니다. 나는 목업의 정확성을 확신하고 싶었다.

Arduino 라이브러리에서 제공하는 일부 지원 기능을 복제하는 코드가 포함 된 mock_arduino.cpp의 소스 :

#include <sys/timeb.h>
#include "mock_arduino.h"

timeb t_start;
unsigned long millis() {
  timeb t_now;
  ftime(&t_now);
  return (t_now.time  - t_start.time) * 1000 + (t_now.millitm - t_start.millitm);
}

void delay( unsigned long ms ) {
  unsigned long start = millis();
  while(millis() - start < ms){}
}

void initialize_mock_arduino() {
  ftime(&t_start);
}

내 코드가 이진 데이터를 하드웨어 직렬 장치에 쓸 때 다음 모형을 사용하여 읽을 수있는 출력을 생성합니다.

fake_serial.h

#include <iostream>

class FakeSerial {
public:
  void begin(unsigned long);
  void end();
  size_t write(const unsigned char*, size_t);
};

extern FakeSerial Serial;

fake_serial.cpp

#include <cstring>
#include <iostream>
#include <iomanip>

#include "fake_serial.h"

void FakeSerial::begin(unsigned long speed) {
  return;
}

void FakeSerial::end() {
  return;
}

size_t FakeSerial::write( const unsigned char buf[], size_t size ) {
  using namespace std;
  ios_base::fmtflags oldFlags = cout.flags();
  streamsize oldPrec = cout.precision();
  char oldFill = cout.fill();

  cout << "Serial::write: ";
  cout << internal << setfill('0');

  for( unsigned int i = 0; i < size; i++ ){
    cout << setw(2) << hex << (unsigned int)buf[i] << " ";
  }
  cout << endl;

  cout.flags(oldFlags);
  cout.precision(oldPrec);
  cout.fill(oldFill);

  return size;
}

FakeSerial Serial;

마지막으로 실제 테스트 프로그램 :

#include "mock_arduino.h"

using namespace std;

void millis_test() {
  unsigned long start = millis();
  cout << "millis() test start: " << start << endl;
  while( millis() - start < 10000 ) {
    cout << millis() << endl;
    sleep(1);
  }
  unsigned long end = millis();
  cout << "End of test - duration: " << end - start << "ms" << endl;
}

void delay_test() {
  unsigned long start = millis();
  cout << "delay() test start: " << start << endl;
  while( millis() - start < 10000 ) {
    cout << millis() << endl;
    delay(250);
  }
  unsigned long end = millis();
  cout << "End of test - duration: " << end - start << "ms" << endl;
}

void run_tests() {
  millis_test();
  delay_test();
}

int main(int argc, char **argv){
  initialize_mock_arduino();
  run_tests();
}

이 게시물은 충분히 길기 때문에 GitHub의 프로젝트 를 참조하여 테스트 사례가 더 있는지 확인하십시오. 나는 마스터 이외의 지점에서 진행중인 작업을 유지하므로 추가 테스트를 위해 해당 지점을 확인하십시오.

저만의 가벼운 테스트 루틴을 작성하기로 선택했지만 CppUnit과 같은보다 강력한 단위 테스트 프레임 워크도 사용할 수 있습니다.


답변

Arduino에 대한 기존 단위 테스트 프레임 워크가 없으면 ArduinoUnit 을 만들었 습니다 . 다음은 그 사용법을 보여주는 간단한 Arduino 스케치입니다.

#include <ArduinoUnit.h>

// Create test suite
TestSuite suite;

void setup() {
    Serial.begin(9600);
}

// Create a test called 'addition' in the test suite
test(addition) {
    assertEquals(3, 1 + 2);
}

void loop() {
    // Run test suite, printing results to the serial port
    suite.run();
}


답변

하드웨어 액세스를 추상화하고 테스트에서 조롱하여 PIC 코드를 테스트하는 데 상당한 성공을 거두었습니다.

예를 들어, 나는 PORTA를

#define SetPortA(v) {PORTA = v;}

그러면 PIC 버전에서 오버 헤드 코드를 추가하지 않고도 SetPortA를 쉽게 조롱 할 수 있습니다.

하드웨어 추상화가 잠시 테스트되면 곧 코드가 테스트 장비에서 PIC로 이동하여 처음으로 작동한다는 것을 곧 알았습니다.

최신 정보:

유닛 코드에 #include 심을 사용하고 # 테스트 리그를위한 C ++ 파일에 유닛 코드를 포함하고 # 타겟 코드를위한 C 파일을 사용합니다.

예를 들어, 4 개의 7 세그먼트 디스플레이, 하나의 포트로 세그먼트를 구동하고 다른 하나는 디스플레이를 선택하여 다중화하고 싶습니다. 통해 디스플레이와 디스플레이 인터페이스 코드 SetSegmentData(char)SetDisplay(char). C ++ 테스트 장비에서 이것을 조롱하고 내가 기대하는 데이터를 얻었는지 확인할 수 있습니다. 대상 #define의 경우 함수 호출의 오버 헤드없이 직접 할당을 얻도록 사용 합니다.

#define SetSegmentData(x) {PORTA = x;}


답변

물리 노가 완벽하게 일을하는 것 같습니다 .

Emulino는 Greg Hewgill의 Arduino 플랫폼 용 에뮬레이터입니다. ( 소스 )

GitHub 리포지토리


답변

simavr 은 avr-gcc를 사용 하는 AVR 시뮬레이터 입니다.

이미 몇 가지 ATTiny 및 ATMega 마이크로 컨트롤러를 지원하며 저자에 따르면 더 쉽게 추가 할 수 있습니다.

예제에는 아두 이노 에뮬레이터 인 simduino가 있습니다. Arduino 부트 로더 실행을 지원하며 Socat (수정 된 Netcat )를 통해 avrdude로 프로그래밍 할 수 있습니다 .


답변

내 프로젝트 PySimAVR을 사용 하여 Python에서 단위 테스트를 할 수 있습니다 . Arscons 는 시뮬레이션을 위해 건물 및 simavr 에 사용됩니다 .

예:

from pysimavr.sim import ArduinoSim
def test_atmega88():
    mcu = 'atmega88'
    snippet = 'Serial.print("hello");'

    output = ArduinoSim(snippet=snippet, mcu=mcu, timespan=0.01).get_serial()
    assert output == 'hello'

테스트 시작 :

$ nosetests pysimavr/examples/test_example.py
pysimavr.examples.test_example.test_atmega88 ... ok


답변

Arduino 코드를 테스트 할 수있는 플랫폼을 알지 못합니다.

그러나 Fritzing 플랫폼 이 있습니다.이 플랫폼을 사용하면 하드웨어를 모델링하고 나중에 PCB 다이어그램과 자료를 내보낼 수 있습니다.

확인 가치가 있습니다.