임베디드시스템의 테스트 주도 개발: 예제코드

예제코드 zip 다운로드

Table of Contents

CppUTest 예제

tests/test_add.cpp

#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"

extern "C"
{
#include "add.h"
}

#define OK 1

TEST_GROUP(Add)
{
    static int mock_send_serial(int value) {

        return mock().actualCall("send_serial").withParameter("value",value).returnValue().getIntValue();
    }
    void setup()
    {
    }
    void teardown()
    {
    }
};

TEST(Add, simple_case)
{

    LONGS_EQUAL(2,add(1,1));
}

TEST(Add, send_added_result)
{
    mock().expectOneCall("send_serial").withParameter("value",7).andReturnValue(OK);
    send_added_result(3,4);
}

src/add/add.c

#include "add.h"

int add(int x, int y)
{
    return x+y;
}

include/add.h

int add(int x,int y);

tests/AllTests.cpp

#include "CppUTest/CommandLineTestRunner.h"
#include "CppUTest/TestPlugin.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTestExt/MockSupportPlugin.h"

int main(int ac, char** av)
{
        MockSupportPlugin mockPlugin;

        TestRegistry::getCurrentRegistry()->installPlugin(&mockPlugin);
        return CommandLineTestRunner::RunAllTests(ac, av);
}

#include "AllTests.h"

tests/AllTests.h

IMPORT_TEST_GROUP(Add);

arduino 예제 프로그램

src/main.cpp

#include <WProgram.h>

int ledPin = 13; // LED connected to digital pin 13
int inPin= 5; // button connected to digital pin 5
int val;

void setup()
{
    pinMode(ledPin, OUTPUT); // sets the digital pin as output
    pinMode(inPin, INPUT); // sets the digital pin as input
    Serial.begin(38400); //baud rate
}

void loop()
{
    unsigned long ctime=millis();
    val = digitalRead(inPin); // read the input pin
    digitalWrite(ledPin, val); // sets the LED to the button's value
    Serial.print(val, DEC); // write to the serial port as the decimal value represented as characters
}

int main(void)
{
    init();
    setup();
    for (;;) {
        loop();
    }
}

Makefile

#Set this to @ to keep the makefile quiet
SILENCE = @

#---- Outputs ----#
COMPONENT_NAME = Add
TARGET_LIB = \
lib/lib$(COMPONENT_NAME).a 

TEST_TARGET = \
$(COMPONENT_NAME)_tests

#--- Inputs ----#
PROJECT_HOME_DIR = .
CPPUTEST_HOME = ../CppUTest

CPPUTEST_USE_EXTENSIONS = Y
CPP_PLATFORM = Gcc

##
WARNINGFLAGS += -Wall -Wswitch-default -Wswitch-enum 
MEMLEAK_DETECTOR_NEW_MACROS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
MEMLEAK_DETECTOR_MALLOC_MACROS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h

ifeq ($(CPPUTEST_USE_MEM_LEAK_DETECTION), N)
CPPUTEST_CPPFLAGS += -DCPPUTEST_MEM_LEAK_DETECTION_DISABLED
endif

ifeq ($(ENABLE_DEBUG), Y)
CPPUTEST_CPPFLAGS += -g
endif

ifeq ($(CPPUTEST_USE_STD_CPP_LIB), N)
CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_CPP_LIB_DISABLED
CPPUTEST_CXXFLAGS += -nostdinc++
endif

CPPUTEST_CPPFLAGS += $(WARNINGFLAGS)
CPPUTEST_CXXFLAGS += $(MEMLEAK_DETECTOR_NEW_MACROS)
CPPUTEST_CFLAGS += $(MEMLEAK_DETECTOR_MALLOC_MACROS)
##
#GCOVFLAGS = -fprofile-arcs -ftest-coverage

#SRC_DIRS is a list of source directories that make up the target library
#If test files are in these directories, their IMPORT_TEST_GROUPs need
#to be included in main to force them to be linked in.  By convention
#put them into an AllTests.h file in each directory
SRC_DIRS = \
src/* \

#TEST_SRC_DIRS is a list of directories including 
# - A test main (AllTests.cpp by conventin)
# - OBJ files in these directories are included in the TEST_TARGET
# - Consequently - AllTests.h containing the IMPORT_TEST_GROUPS is not needed
# - 
TEST_SRC_DIRS = \
tests \

#includes for all compiles
INCLUDE_DIRS =\
  $(CPPUTEST_HOME)/include/\
  include/\
  mocks/\
  tests/\

#Flags to pass to ld
LDFLAGS +=
LD_LIBRARIES += -lstdc++

include $(CPPUTEST_HOME)/build/ComponentMakefile

# Next: Makefile for AVR
# MCU
MCU = atmega168
F_CPU = 7372800L

TARGET = $(COMPONENT_NAME)

# AVRDUDE
PORT=COM1 # TODO: Change Serial Port
BAUD=19200
PROTOCOL=stk500v1
PART=m168
AVRDUDE=avrdude

# Directory 
DIR_ARDUINO = lib/ArduinoCore
CUT_INCLUDE = include
DIR_SRC = src
CUT_SRC = src/add

# Objects
OBJS =  # src objs file
CUT_OBJS = add.o  # src/keyboard objs file
CPP_OBJS = main.o # main.cpp

AVR_CFLAGS =  -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=$(MCU) -DF_CPU=$(F_CPU) -I$(DIR_ARDUINO) -I$(CUT_INCLUDE)
AVR_CPPFLAGS =  -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=$(MCU) -DF_CPU==$(F_CPU) -I$(DIR_ARDUINO) -I$(CUT_INCLUDE) -I$(DIR_SRC)

RM := rm -rf

# All Target
upload: OBJS += $(CUT_OBJS) 
upload: OBJS += $(CPP_OBJS) 
upload: elf secondary-outputs 
upload: avrclean

$(CUT_OBJS): %.o: $(CUT_SRC)/%.c
    @echo 'Compile '
    avr-gcc $(AVR_CFLAGS) $< -o $@

$(OBJS): %.o: $(DIR_SRC)/%.c
    @echo 'Compile '
    avr-gcc $(AVR_CFLAGS) $< -o $@


$(CPP_OBJS): %.o: $(DIR_SRC)/%.cpp
    @echo ' '
    avr-g++ $(AVR_CPPFLAGS) $< -o $@

elf: $(OBJS) $(CUT_OBJS) $(CPP_OBJS)
    @echo 'Building target: $(TARGET)'
    @echo 'Invoking: AVR C++ Linker'
    avr-gcc -Os -Wl,--gc-sections -mmcu=$(MCU) -o $(TARGET).elf $(OBJS) $(DIR_ARDUINO)/Debug/libArduinoCore.a -L"../../ArduinoCore" -lm
    @echo 'Finished building target: $(TARGET)'
    @echo ' '

lss: 
    @echo 'Invoking: AVR Create Extended Listing'
    avr-objdump -h -S $(TARGET).elf > $(TARGET).lss
    @echo 'Finished building: $(TARGET)'
    @echo ' '

hex: 
    @echo 'Create Flash image (ihex format)'
    avr-objcopy -R .eeprom -O ihex $(TARGET).elf $(TARGET).hex
    @echo 'Finished building: $@'
    @echo ' '

size:
    @echo 'Invoking: Print Size'
    avr-size --format=avr --mcu=$(MCU) $(TARGET).elf
    @echo 'Finished building: $@'
    @echo ' '

avrdude: 
    @echo 'Invoking: AVRDude'
    $(AVRDUDE) -p$(PART) -carduino -P$(PORT) -b$(BAUD) -F -Uflash:w:$(TARGET).hex:a
    @echo 'Finished building: $@'
    @echo ' '

avrclean:
    $(RM) $(OBJS)$(C_DEPS)$(ELFS) *.lss *.hex $(S_DEPS)$(CXX_DEPS)$(S_UPPER_DEPS)$(C++_DEPS)$(ASM_DEPS)$(CC_DEPS)$(CPP_DEPS)$(C_UPPER_DEPS) *.elf *.o
    @echo ' '

secondary-outputs: lss hex size avrdude

.PHONY: upload dependents

.SECONDARY:

파이썬에서 시리얼 통신

serialmonitor.py

import serial,sys

print "> entered"
s=serial.Serial("Com1", 38400)

s.flush()
print "> serial opened"

def linereader(s):
    b=[]
    while True:
        b.append(s.read())
        if b[-1]=='\n':
            yield ''.join(b)
            b=[]

lr=linereader(s)

try:
    while True:
    for i in lr:
            sys.stdout.write(i)
        sys.stdout.flush()
finally:
    s.close()

read_keystep.py

import serial, sys
filename = 'i.log'
print "> entered"
s=serial.Serial("Com1", 38400)
s.flush()
print "> serial opened"
f=open(filename,'w')
event = None
value = None
i=0

try:
    while True:
        event = s.read()
        if event not in '012':
            print "unexpected input: %s"%repr(event)
            continue
        e = int(event)
        if e == 0:
            event = 'NOEVT'
        elif e == 1:
            event = 'PRESSED'
        elif e == 2:
            event = 'RELEASED'
        if event=='PRESSED':
            sys.stdout.write('P')
        if event=='RELEASED':
            sys.stdout.write('R')
            sys.stdout.write('%03d\n'%i)
            i+=1

        sys.stdout.flush()
        f.flush()
finally:
    f.close()
    s.close()

파이썬으로 키보드 'a' 키 입력

import ctypes

ctypes.windll.user32.keybd_event(ord("A"),0,0,0) #press
ctypes.windll.user32.keybd_event(ord("A"),0,2,0) #release

Date: 2010-12-23 13:34:05