Atualmente exitem diversas metodologias para o desenvolvimento de software de alto nível para computadores pessoais. Algumas dessas metodologias estão sendo adaptadas para realidade de sistemas embarcados, como por exemplo, o desenvolvimento orientado a testes (TDD – Test Driven Development). Diferentemente da abordagem convencional onde todo o código é desenvolvido e apenas depois os testes (e a busca por bugs) são realizados, nesta metodologia o código é desenvolvido de forma incremental juntamente com a rotina de testes. As principais vantagens são:
- Sistema tende ser melhor projetado, melhorando-se a qualidade do código;
- Ao final do projeto, o código já foi exercitado por uma bateria de testes;
- A cada alteração no código fonte, refazer os testes é trivial;
- Evita-se a pressão de realizar testes/debug o mais rápido possível ao final do projeto;
- Entre vários outros.
Para facilitar o trabalho do desenvolvedor, existem vários frameworks para testes unitários em C, dentre eles o Unity. Basicamente o Unity é um conjunto de macros e funções que possibilitam o desenvolvedor automatizar testes unitários. Como não cobriremos neste post como funciona o Unity, deixamos como referência o livro Test Driven Development for Embedded C de James Grenning. Além do Unity, este livro é uma introdução à metodologia TDD e também mostra vários exemplos de como escrever os códigos de testes.
Vamos criar um pequeno projeto para mostrar como configurar e como o TDD pode ser usado com microcontroladores Microchip, no caso o PIC24FJ256GA106. Usaremos uma ferramenta chamada ceedling que gera automaticamente todo o ambiente necessário para se usar o Unity. Lembrando apenas que o exemplo é em uma máquina com Linux e o IDE usado para o projeto com o PIC é o MPLAB x IDE. (Veja os links de referência para saber como instalar o ceedling, como configurar em ambiente Windows e vários exemplos práticos).
1) Dentro da pasta de projetos do mplabx (geralmente o nome da pasta termina com .X), crie um projeto novo com o ceedling.
1 |
ceedling new teste_unitario |
2) Dentro desta pasta, encontra-se o arquivo de configuração do projeto. Para o nosso exemplo, iremos adaptar ele para usar o compilador microchip xc16-gcc e seu simulador sim30. O arquivo de configuração deve ficar assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
:project: :use_exceptions: FALSE :use_test_preprocessor: FALSE :use_auxiliary_dependencies: TRUE :build_root: build :test_file_prefix: test_ :extension: :executable: .out :paths: :include: - /opt/microchip/xc16/v1.11/support/PIC24F/h - /opt/microchip/xc16/v1.11/include/ :test: - +:test/** - -:test/support :source: - ../** :support: - test/support :defines: # in order to add common defines: # 1) remove the trailing [] from the :common: section # 2) add entries to the :common: section (e.g. :test: has TEST defined) :commmon: &common_defines - __PIC24FJ256GA106__ #- UNITY_EXCLUDE_STDINT_H - UNITY_INT_WIDTH=16 - CMOCK_MEM_INDEX_TYPE=uint16_t - CMOCK_MEM_PTR_AS_INT=uint16_t - CMOCK_MEM_ALIGN=1 - CMOCK_MEM_SIZE=4096 :test: - *common_defines :test_preprocess: - *common_defines :cmock: :mock_prefix: mock_ :when_no_prototypes: :warn :enforce_strict_ordering: TRUE :plugins: - :ignore - :callback - :array :treat_as: uint8: HEX8 uint16: HEX16 uint32: UINT32 int8: INT8 bool: UINT8 :when_ptr: - :smart #:tools: # Ceedling defaults to using gcc for compiling, linking, etc. # As [:tools] is blank, gcc will be used (so long as it's in your system path) # See documentation to configure a given toolchain for use :tools: :test_compiler: :executable: xc16-gcc :arguments: - -mcpu=24FJ256GA106 - -x c - -c - -g - -omf=elf - "${1}" - -o "${2}" - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR - -I"./" - -Wall - -mlarge-code - -mlarge-data - -mlarge-scalar - -mconst-in-code - -msmart-io=1 - -msfr-warn=off :test_linker: :executable: xc16-gcc :arguments: - -mcpu=24FJ256GA106 - -omf=elf - ${1} - -o "./build/test.out" - -Wl,-Tp24FJ256GA106.gld,-Map=./build/test.map,--report-mem :test_fixture: :executable: ruby :name: "Microchip simulator test fixture" :stderr_redirect: :UNIX #inform Ceedling what model of $stderr capture to use :arguments: - test/simulation/sim_test_fixture.rb :release_compiler: :executable: xc16-gcc :arguments: - -x c - -c - -g - -omf=elf - "${1}" - -o "${2}" - -mcpu=24FJ256GA106 - -Wall - -Werror - -Os - -mlarge-code - -mlarge-arrays - -mlarge-data - -mlarge-scalar - -mconst-in-code - -msmart-io=1 - -msfr-warn=off - -I"$": COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR - -I"$": COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE - -D$: COLLECTION_DEFINES_RELEASE_AND_VENDOR :release_linker: :executable: xc16-gcc :arguments: - -mcpu=24FJ256GA106 - ${1} - -o "${2}" - -omf=elf - -Wl,--defsym=__MPLAB_BUILD=1,,--script="p24FJ256GA106.gld",--check-sections,--data-init,--pack-data,--handles,--isr,--no-gc-sections,--fill-uper=0,--stackguard=16,--no-force-link,--smart-io,--report-mem :plugins: :load_paths: - vendor/ceedling/plugins :enabled: - stdout_pretty_tests_report - module_generator ... |
Nota1: Adicione o path do compilador no PATH do sistema.
Nota2: Nesta máquina o compilador está instalado em /opt/microchip/xc16/v1.11, e no arquivo de configuração as bibliotecas padrões são configuradas na seção:
1 2 3 4 |
:paths: :include: - /opt/microchip/xc16/v1.11/support/PIC24F/h - /opt/microchip/xc16/v1.11/include/ |
3) Dentro da pasta teste_unitario/test, crie uma pasta chamada simulation:
1 2 |
cd test mkdir simulation |
4) Em teste_unitario/test/simulation crie um arquivo chamado sim_instructions.txt e edite-o desta forma:
1 2 3 4 5 6 |
LD pic24super LC ./build/test.out IO NULL ./test/simulation/out.txt RP E quit |
5) Em teste_unitario/test/simulation crie um arquivo chamado sim_test_fixture.rb e edite-o desta forma:
1 2 3 4 5 6 7 8 9 |
OUT_FILE = "./test/simulation/out.txt" File.delete OUT_FILE if File.exists? OUT_FILE IO.popen("sim30 ./test/simulation/sim_instructions.txt") sleep 1 if File.exists? OUT_FILE file_contents = File.read OUT_FILE file_contents.gsub!("\n", "") print file_contents end |
6) Adicione o código de testes em teste_unitario/test. Vale lembrar que podemos configurar o path do código fonte tanto do projeto como dos testes para apontar em qualquer outro diretório. Para isso, altere o arquivo do projeto na seção :paths:source e :path:test respectivamente.
7) Para rodar todos os testes digite:
1 |
rake test:all |
ou então para rodar um teste em específico, digite rake test:test_<nome_do_teste>. No nosso caso, o teste chama-se “misc”:
1 |
rake test:test_misc |
Referências
Imagem destacada: FreeDigitalPhotos.net
ótimo artigo