Pergunta

Trabalhei em um sistema embarcado neste verão escrito em C direto.Era um projeto existente que a empresa em que trabalho assumiu.Fiquei bastante acostumado a escrever testes de unidade em Java usando JUnit, mas não sabia qual a melhor maneira de escrever testes de unidade para código existente (que precisava de refatoração), bem como para novo código adicionado ao sistema.

Existe alguma maneira de tornar o teste de unidade de código C simples tão fácil quanto o teste de unidade de código Java com, por exemplo, JUnit?Qualquer visão que se aplique especificamente ao desenvolvimento embarcado (compilação cruzada para a plataforma arm-linux) seria muito apreciada.

Foi útil?

Solução

Uma estrutura de teste de unidade em C é Verificar;uma lista de estruturas de teste de unidade em C pode ser encontrada aqui e está reproduzido abaixo.Dependendo de quantas funções de biblioteca padrão seu tempo de execução possui, você pode ou não conseguir usar uma delas.

Unidade Ace

AceUnit (Advanced C and Embedded Unit) se autodenomina uma confortável estrutura de teste de unidade de código C.Ele tenta imitar o JUnit 4.x e inclui recursos semelhantes aos de reflexão.AceUnit pode ser usado em ambientes com restrição de recursos, por ex.desenvolvimento de software incorporado e, mais importante, funciona bem em ambientes onde você não pode incluir um único arquivo de cabeçalho padrão e não pode invocar uma única função C padrão das bibliotecas ANSI/ISO C.Ele também possui uma porta Windows.Ele não usa garfos para capturar sinais, embora os autores tenham manifestado interesse em adicionar tal recurso.Veja o Página inicial da AceUnit.

Unidade automática GNU

Muito parecido com o Check, incluindo bifurcação para executar testes de unidade em um espaço de endereço separado (na verdade, o autor original do Check pegou emprestada a ideia do GNU Autounit).GNU Autounit usa GLib extensivamente, o que significa que links e similares precisam de opções especiais, mas isso pode não ser um grande problema para você, especialmente se você já estiver usando GTK ou GLib.Veja o Página inicial do GNU Autounit.

cUnit

Também usa GLib, mas não bifurca para proteger o espaço de endereço de testes unitários.

Unidade C

Padrão C, com planos para implementação de GUI Win32.Atualmente, não bifurca nem protege de outra forma o espaço de endereço dos testes de unidade.No início do desenvolvimento.Veja o Página inicial do CUnit.

CuTest

Uma estrutura simples com apenas um arquivo .c e um arquivo .h que você coloca em sua árvore de origem.Veja o Página inicial do CuTest.

Unidade Cpp

A principal estrutura de testes unitários para C++;você também pode usá-lo para testar o código C.É estável, desenvolvido ativamente e possui uma interface GUI.Os principais motivos para não usar CppUnit para C são, primeiro, que ele é muito grande e, segundo, você precisa escrever seus testes em C++, o que significa que você precisa de um compilador C++.Se isso não parecer uma preocupação, definitivamente vale a pena considerar, junto com outras estruturas de teste de unidade C++.Veja o Página inicial do CppUnit.

embUnit

embUnit (Embedded Unit) é outra estrutura de teste de unidade para sistemas embarcados.Este parece ter sido substituído pelo AceUnit. Página inicial da unidade incorporada.

Unidade mínima

Um conjunto mínimo de macros e pronto!O objetivo é mostrar como é fácil testar a unidade do seu código.Veja o Página inicial da MinUnit.

CUnit para o Sr.Ando

Uma implementação CUnit que é relativamente nova e aparentemente ainda em desenvolvimento inicial.Veja o CUnit para o Sr.Página inicial do Ando.

Esta lista foi atualizada pela última vez em março de 2008.

Mais estruturas:

CMocka

CMocka é uma estrutura de teste para C com suporte para objetos simulados.É fácil de usar e configurar.

Ver a página inicial do CMocka.

Critério

Criterion é uma estrutura de teste de unidade C multiplataforma que suporta registro automático de testes, testes parametrizados, teorias e que pode gerar vários formatos, incluindo TAP e JUnit XML.Cada teste é executado em seu próprio processo, portanto, sinais e falhas podem ser relatados ou testados, se necessário.

Veja o Página inicial do critério Para maiores informações.

HWUT

HWUT é uma ferramenta geral de teste de unidade com excelente suporte para C.Ele pode ajudar a criar Makefiles, gerar casos de teste massivos codificados em 'tabelas de iteração' mínimas, percorrer máquinas de estado, gerar C-stubs e muito mais.A abordagem geral é bastante única:Os veredictos são baseados em 'stdout bom/padrão ruim'.A função de comparação, porém, é flexível.Assim, qualquer tipo de script pode ser utilizado para verificação.Pode ser aplicado a qualquer linguagem que possa produzir saída padrão.

Ver a página inicial do HWUT.

CVerde

Uma estrutura de simulação e teste de unidade moderna, portátil e multilíngue para C e C++.Ele oferece uma notação BDD opcional, uma biblioteca de simulação e a capacidade de executá-la em um único processo (para facilitar a depuração).Um executor de testes que descobre automaticamente as funções de teste está disponível.Mas você pode criar o seu próprio programaticamente.

Todos esses recursos (e mais) são explicados em o manual CGreen.

A Wikipedia fornece uma lista detalhada de estruturas de teste de unidade C em Lista de estruturas de teste unitário:C

Outras dicas

Pessoalmente gosto do Estrutura de teste do Google.

A verdadeira dificuldade em testar o código C é quebrar as dependências de módulos externos para que você possa isolar o código em unidades.Isso pode ser especialmente problemático quando você está tentando fazer testes em código legado.Nesse caso, muitas vezes me pego usando o vinculador para usar funções stubs em testes.

É a isso que as pessoas se referem quando falam sobre "costuras".Em C, sua única opção é usar o pré-processador ou o vinculador para simular suas dependências.

Um conjunto de testes típico em um dos meus projetos C pode ser assim:

#include "myimplementationfile.c"
#include <gtest/gtest.h>

// Mock out external dependency on mylogger.o
void Logger_log(...){}

TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}

Observe que você está incluindo o arquivo C e não o arquivo de cabeçalho.Isto dá a vantagem de acesso a todos os membros de dados estáticos.Aqui eu zombo do meu logger (que pode estar em logger.o e forneço uma implementação vazia.Isso significa que o arquivo de teste é compilado e vinculado independentemente do restante da base de código e executado isoladamente.

Quanto à compilação cruzada do código, para que isso funcione você precisa de boas instalações no alvo.Eu fiz isso com o googletest compilado para Linux em uma arquitetura PowerPC.Isso faz sentido porque aí você tem um shell completo e um sistema operacional para coletar seus resultados.Para ambientes menos ricos (que classifico como qualquer coisa sem um sistema operacional completo), você deve apenas compilar e executar no host.Você deve fazer isso de qualquer maneira para poder executar os testes automaticamente como parte da compilação.

Acho que testar o código C++ geralmente é muito mais fácil devido ao fato de que o código OO é em geral muito menos acoplado do que o processual (é claro que isso depende muito do estilo de codificação).Também em C++ você pode usar truques como injeção de dependência e substituição de método para inserir costuras em código que de outra forma seria encapsulado.

Michael Feathers tem um excelente livro sobre teste de código legado.Em um capítulo ele aborda técnicas para lidar com código não-OO que eu recomendo fortemente.

Editar:Eu escrevi um postagem no blog sobre código processual de teste de unidade, com fonte disponível no GitHub.

Editar:Existe um novo livro saindo dos Pragmatic Programmers que aborda especificamente o código C de teste de unidade que Eu recomendo.

Unidade mínima é uma estrutura de teste de unidade incrivelmente simples.Estou usando-o para testar a unidade do código do microcontrolador C para AVR.

Atualmente estou usando a estrutura de teste de unidade CuTest:

http://cutest.sourceforge.net/

É ideal para sistemas embarcados porque é muito leve e simples.Não tive problemas para fazê-lo funcionar na plataforma de destino e também no desktop.Além de escrever os testes unitários, tudo o que é necessário é:

  • Um arquivo de cabeçalho incluído onde quer que você esteja chamando as rotinas mais fofas
  • Um único arquivo 'C' adicional a ser compilado/vinculado à imagem
  • algum código simples adicionado ao principal para configurar e chamar os testes unitários - I basta ter isso em um main() especial função que é compilada se UNITTEST é definido durante o construir.

O sistema precisa suportar um heap e algumas funcionalidades stdio (que nem todos os sistemas embarcados possuem).Mas o código é simples o suficiente para que você provavelmente possa trabalhar em alternativas a esses requisitos se sua plataforma não os tiver.

Com algum uso criterioso de blocos "C"{} externos, ele também suporta testes de C++ perfeitamente.

Eu digo quase o mesmo que ratkok, mas se você tiver uma variação incorporada nos testes de unidade, então ...

Unidade - Estrutura altamente recomendada para teste de unidade de código C.

Os exemplos do livro mencionado neste tópico TDD para C incorporado são escritos usando Unity (e CppUTest).

Você também pode querer dar uma olhada libtap, uma estrutura de teste C que gera o Test Anything Protocol (TAP) e, portanto, se integra bem com uma variedade de ferramentas lançadas para esta tecnologia.É usado principalmente no mundo da linguagem dinâmica, mas é fácil de usar e está se tornando muito popular.

Um exemplo:

#include <tap.h>

int main () {
    plan(5);

    ok(3 == 3);
    is("fnord", "eek", "two different strings not that way?");
    ok(3 <= 8732, "%d <= %d", 3, 8732);
    like("fnord", "f(yes|no)r*[a-f]$");
    cmp_ok(3, ">=", 10);

    done_testing();
}

Existe uma estrutura elegante de testes unitários para C com suporte para objetos simulados chamados cmocka.Requer apenas a biblioteca C padrão, funciona em diversas plataformas de computação (inclusive embarcadas) e com diferentes compiladores.

Ele também tem suporte para diferentes formatos de saída de mensagens, como Subunit, Test Anything Protocol e relatórios jUnit XML.

cmocka foi criado para funcionar também em plataformas embarcadas e também possui suporte para Windows.

Um teste simples é assim:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
    (void) state; /* unused */
}

int main(void) {
    const struct CMUnitTest tests[] = {
        cmocka_unit_test(null_test_success),
    };
    return cmocka_run_group_tests(tests, NULL, NULL);
}

O API está totalmente documentado e vários exemplos fazem parte do código-fonte.

Para começar com cmocka você deve ler o artigo em LWN.net: Teste de unidade com objetos simulados em C

cmocka 1.0 foi lançado em fevereiro de 2015.

Não fui muito longe testando um aplicativo C legado antes de começar a procurar uma maneira de simular funções.Eu precisava muito de simulações para isolar o arquivo C que desejo testar de outros.Experimentei o cmock e acho que vou adotá-lo.

O Cmock verifica arquivos de cabeçalho e gera funções simuladas com base nos protótipos que encontra.As simulações permitirão que você teste um arquivo C em perfeito isolamento.Tudo o que você terá que fazer é vincular seu arquivo de teste a simulações em vez de seus arquivos de objeto reais.

Outra vantagem do cmock é que ele validará os parâmetros passados ​​para funções simuladas e permitirá especificar qual valor de retorno os simulados devem fornecer.Isto é muito útil para testar diferentes fluxos de execução em suas funções.

Os testes consistem nas funções típicas testA(), testB() nas quais você cria expectativas, chama funções para testar e verificar afirmações.

A última etapa é gerar um executor para seus testes com unidade.Cmock está vinculado à estrutura de teste de unidade.Unity é tão fácil de aprender quanto qualquer outra estrutura de teste de unidade.

Vale a pena tentar e é muito fácil de entender:

http://sourceforge.net/apps/trac/cmock/wiki

Atualização 1

Outra estrutura que estou investigando é o Cmockery.

http://code.google.com/p/cmockery/

É uma estrutura C pura que oferece suporte a testes de unidade e simulação.Não depende de Ruby (ao contrário do Cmock) e muito pouca dependência de bibliotecas externas.

Requer um pouco mais de trabalho manual para configurar simulações porque não gera código.Isso não representa muito trabalho para um projeto existente, já que os protótipos não mudarão muito:depois de ter seus mocks, você não precisará alterá-los por um tempo (este é o meu caso).A digitação extra fornece controle completo das simulações.Se houver algo que você não gosta, basta alterar sua simulação.

Não há necessidade de um executor de testes especial.Você só precisa criar uma matriz de testes e passá-la para uma função run_tests.Um pouco mais de trabalho manual aqui também, mas definitivamente gosto da ideia de uma estrutura autônoma e independente.

Além disso, contém alguns truques C bacanas que eu não conhecia.

No geral, o Cmockery precisa de um pouco mais de compreensão sobre simulações para começar.Os exemplos devem ajudá-lo a superar isso.Parece que pode fazer o trabalho com uma mecânica mais simples.

Como novato em C, encontrei os slides chamados Desenvolvimento orientado a testes em C muito útil.Basicamente, ele usa o padrão assert() junto com && para entregar uma mensagem, sem quaisquer dependências externas.Se alguém está acostumado com uma estrutura de teste full stack, isso provavelmente não funcionará :)

Unidade C

E Unidade incorporada é uma estrutura de teste de unidade para sistema C incorporado.Seu design foi copiado do JUnit e CUnit e mais, e então adaptado para o Embedded C System.A unidade incorporada não requer bibliotecas C padrão.Todos os objetos são alocados na área const.

E Tessy automatiza o teste de unidade de software embarcado.

Eu não uso uma estrutura, apenas uso o suporte de destino de "verificação" do autotools.Implemente um "principal" e use assert(s).

Meu diretório de teste Makefile.am(s) se parece com:

check_PROGRAMS = test_oe_amqp

test_oe_amqp_SOURCES = test_oe_amqp.c
test_oe_amqp_LDADD = -L$(top_builddir)/components/common -loecommon
test_oe_amqp_CFLAGS = -I$(top_srcdir)/components/common -static

TESTS = test_oe_amqp

Nós escrevemos TRAIR (hospedado em GitHub) para fácil usabilidade e portabilidade.

Não possui dependências e não requer instalação ou configuração.Apenas um arquivo de cabeçalho e um caso de teste são necessários.

#include <cheat.h>

CHEAT_TEST(mathematics_still_work,
    cheat_assert(2 + 2 == 4);
    cheat_assert_not(2 + 2 == 5);
)

Os testes são compilados em um executável que se encarrega de executá-los e relatar seus resultados.

$ gcc -I . tests.c
$ ./a.out
..
---
2 successful of 2 run
SUCCESS

Tem cores lindas também.

O livro de Michael Feather "Working Effectively with Legacy Code" apresenta muitas técnicas específicas para testes unitários durante o desenvolvimento C.

Existem técnicas relacionadas à injeção de dependência específicas de C que não vi em nenhum outro lugar.

CppUTest - Estrutura altamente recomendada para teste de unidade de código C.

Os exemplos do livro mencionado neste tópico TDD para C incorporado são escritos usando CppUTest.

eu uso CxxTeste para um ambiente c/c++ incorporado (principalmente C++).

Eu prefiro CxxTest porque ele possui um script perl/python para construir o executor de testes.Depois de uma pequena inclinação para configurá-lo (menor ainda, já que você não precisa escrever o executor de teste), é muito fácil de usar (inclui exemplos e documentação útil).A maior parte do trabalho foi configurar o 'hardware' que o código acessa para que eu pudesse testar a unidade/módulo com eficiência.Depois disso, é fácil adicionar novos casos de teste unitários.

Conforme mencionado anteriormente, é uma estrutura de teste de unidade C/C++.Então você precisará de um compilador C++.

Guia do usuário CxxTest Wiki CxxTest

além do meu preconceito óbvio

http://code.google.com/p/seatest/

é uma maneira simples e agradável de testar a unidade do código C.imita xUnit

Depois de ler o Minunit, pensei que a melhor maneira seria basear o teste na macro assert, que uso muito como técnica de programa defensivo.Então usei a mesma ideia de Minunit misturada com afirmação padrão.Você pode ver meu framework (um bom nome poderia ser NoMinunit) em blog do k0ga

O Google possui uma excelente estrutura de testes. https://github.com/google/googletest/blob/master/googletest/docs/primer.md

E sim, pelo que vejo, funcionará com C simples, ou seja,não requer recursos C++ (pode exigir compilador C++, não tenho certeza).

Zombaria é um projeto lançado recentemente que consiste em uma biblioteca C muito simples de usar para escrever testes unitários.

Primeiro, veja aqui: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C

Minha empresa possui uma biblioteca C que nossos clientes usam.Usamos CxxTest (uma biblioteca de teste de unidade C++) para testar o código.CppUnit também funcionará.Se você estiver preso em C, recomendo o RCUNIT (mas o CUnit também é bom).

Se você estiver familiarizado com JUnit, recomendo o CppUnit.http://cppunit.sourceforge.net/cppunit-wiki

Isso pressupõe que você tenha um compilador C++ para fazer os testes de unidade.caso contrário, tenho que concordar com Adam Rosenfield que verificar é o que você deseja.

eu usei UNIDADE RC para fazer alguns testes de unidade para código incorporado no PC antes de testar no destino.Uma boa abstração da interface de hardware é importante, caso contrário, o endianismo e os registros mapeados na memória irão matá-lo.

Verificador de integridade da API — estrutura de teste para bibliotecas C/C++:

Um gerador automático de testes de unidade básicos para uma biblioteca C/C++ compartilhada.Ele é capaz de gerar dados de entrada razoáveis ​​​​(na maioria dos casos, mas infelizmente não em todos) para parâmetros e compor casos de teste simples ("sanidade" ou qualidade "superficial") para cada função na API por meio da análise de declarações no cabeçalho arquivos.

A qualidade dos testes gerados permite verificar a ausência de erros críticos em casos de uso simples.A ferramenta é capaz de construir e executar testes gerados e detectar travamentos (segfaults), abortos, todos os tipos de sinais emitidos, código de retorno de programa diferente de zero e travamento de programa.

Exemplos:

Uma técnica a ser usada é desenvolver o código de teste de unidade com uma estrutura C++ xUnit (e um compilador C++), enquanto mantém a fonte do sistema de destino como módulos C.

Certifique-se de compilar regularmente sua fonte C em seu compilador cruzado, automaticamente com seus testes de unidade, se possível.

LibU (http://koanlogic.com/libu) possui um módulo de teste de unidade que permite dependências explícitas de conjuntos de testes/casos, isolamento de testes, execução paralela e um formatador de relatório personalizável (os formatos padrão são xml e txt).

A biblioteca é licenciada por BSD e contém muitos outros módulos úteis - rede, depuração, estruturas de dados comumente usadas, configuração, etc.- caso você precise deles em seus projetos ...

Estou surpreso que ninguém tenha mencionado Cortador (http://cutter.sourceforge.net/)Você pode testar C e C++, ele se integra perfeitamente com ferramentas automáticas e tem um tutorial muito bom disponível.

Caso você esteja visando plataformas Win32 ou modo kernel NT, você deve dar uma olhada em cfix.

Se você ainda está em busca de frameworks de teste, CUnitWin32 é um para a plataforma Win32/NT.

Isso resolve um problema fundamental que enfrentei com outras estruturas de teste.Ou seja, variáveis ​​globais/estáticas estão em um estado determinístico porque cada teste é executado como um processo separado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top