it-swarm-pt.tech

Código C de teste unitário

Eu trabalhei em um sistema embarcado neste verão escrito em linha reta C. Foi um projeto existente que a empresa para a qual trabalhei assumiu. Tornei-me bastante acostumado a escrever testes unitários em Java usando o JUnit, mas fiquei perdendo a melhor maneira de escrever testes de unidade para código existente (que precisava de refatoração), bem como um novo código adicionado ao sistema.

Existe alguma maneira de tornar a unidade testando o código C simples tão fácil quanto testar o código Java com, por exemplo, JUnit? Qualquer insight que se aplicasse especificamente ao desenvolvimento embarcado (cross-compiling para arm-linux platform) seria muito apreciado.

812
Paul Osborne

Uma estrutura de testes unitários em C é Check ; uma lista de estruturas de testes unitários em C pode ser encontrada aqui e é reproduzida abaixo. Dependendo de quantas funções de biblioteca padrão seu tempo de execução possui, você pode ou não ser capaz de usar uma delas.

AceUnit

AceUnit (Advanced C e Embedded Unit) se auto-intitula como uma estrutura de teste de unidade de código C confortável. Ele tenta imitar o JUnit 4.xe inclui capacidades de reflexão. AceUnit pode ser usado em ambientes de restrição de recursos, por ex. desenvolvimento de software incorporado e, mais importante, ele é executado bem em ambientes em que 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. Também possui uma porta do Windows. Ele não usa garfos para interceptar sinais, embora os autores tenham expressado interesse em adicionar tal recurso. Veja o Homepage do AceUnit .

GNU Autounit

Muito ao longo das mesmas linhas como Check, incluindo o forking para executar testes de unidade em um espaço de endereço separado (na verdade, o autor original do Check emprestou a ideia de GNU Autounit). GNU O Autounit usa o GLib extensivamente, o que significa que links e outros precisam de opções especiais, mas isso pode não ser um grande problema para você, especialmente se você já estiver usando o GTK ou o GLib. Veja o homepage GNU Autounit .

cUnit

Também usa o GLib, mas não bifurca para proteger o espaço de endereço dos testes de unidade.

CUnit

Padrão C, com planos para uma implementação de GUI do Win32. Atualmente não bifurca ou protege o espaço de endereço dos testes de unidade. No início do desenvolvimento. Veja o Homepage CUnit .

CuTest

Um framework simples com apenas um arquivo .c e um .h que você coloca na sua árvore de fontes. Veja o homepage do CuTest .

CppUnit

O principal framework 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. As principais razões para não usar CppUnit para C são as primeiras que são grandes, e segundo você tem que escrever seus testes em C++, o que significa que você precisa de um compilador C++. Se isso não parecer preocupação, definitivamente vale a pena considerar, juntamente com outras estruturas de teste de unidade do C++. Veja o homepage CppUnit .

embUnit

embUnit (Embedded Unit) é outra estrutura de teste de unidade para sistemas embarcados. Este parece ser substituído pelo AceUnit. homepage da Unidade Embarcada .

MinUnit

Um conjunto mínimo de macros e pronto! O objetivo é mostrar como é fácil testar seu código em unidade. Veja o MinUnit homepage .

CUnit para o Sr. Ando

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

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

Mais frameworks:

CMocka

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

Veja a página inicial do CMocka .

Critério

O Criterion é uma estrutura de teste de unidade C de plataforma cruzada que suporta registro de teste automático, 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 Homepage do Critério para mais informações.

HWUT

HWUT é uma ferramenta geral de Testes Unitários com grande suporte para C. Ela pode ajudar a criar Makefiles, gerar casos de teste massivos codificados em 'tabelas de iteração' mínimas, caminhar ao longo de máquinas de estado, gerar stubs C e muito mais. A abordagem geral é bastante singular: os veredictos são baseados em 'boa stdout/má stdout'. A função de comparação, no entanto, é flexível. Assim, qualquer tipo de script pode ser usado para verificação. Pode ser aplicado a qualquer idioma que possa produzir saída padrão.

Veja a homepage do HWUT .

CGreen

Um moderno, portátil, cross-language testando e mocking framework para C e C++. Ele oferece uma notação BDD opcional, uma biblioteca de simulação, a capacidade de executá-lo em um único processo (para facilitar a depuração). Um corredor de teste que descobre automaticamente as funções de teste está disponível. Mas você pode criar seus próprios programaticamente.

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

A Wikipedia fornece uma lista detalhada de estruturas de testes unitários em C em Lista de estruturas de testes unitários: C

463
Adam Rosenfield

Pessoalmente eu gosto do framework de teste do Google .

A dificuldade real em testar o código C está quebrando as dependências dos módulos externos para que você possa isolar o código em unidades. Isso pode ser especialmente problemático quando você está tentando obter testes sobre o código legado. Nesse caso, frequentemente me encontro usando o vinculador para usar funções de stubs em testes.

Isto é o que as pessoas estão se referindo quando falam sobre " costuras ". Em C, sua única opção é realmente usar o pré-processador ou o linker para ridicularizar suas dependências.

Um conjunto de testes típico em um dos meus projetos em C pode ter esta aparência:

#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 . Isso dá a vantagem de acesso a todos os membros de dados estáticos. Aqui eu mexo meu logger (que pode estar em logger.o e dou uma implementação vazia. Isso significa que o arquivo de teste compila e liga independentemente do resto da base de código e executa em isolamento.

Quanto à compilação cruzada do código, para que isso funcione, você precisa de boas instalações no destino. Eu fiz isso com o googletest cross compilado para o Linux em uma arquitetura PowerPC. Isso faz sentido porque você tem um Shell e um completos para reunir seus resultados. Para ambientes menos ricos (que eu classifico como qualquer coisa sem um SO completo) você deve apenas construir e rodar no Host. Você deve fazer isso de qualquer maneira para poder executar os testes automaticamente como parte da construção.

Eu acho que o teste de código C++ é geralmente muito mais fácil devido ao fato de que o código OO é em geral muito menos acoplado do que 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étodos para obter costuras no código que é encapsulado de outra forma.

Michael Feathers tem um excelente livro sobre como testar código herdado . Em um capítulo, ele aborda técnicas para lidar com código não OO, o que eu recomendo.

Edit : Eu escrevi um post no blog sobre código procedural de teste unitário, com fonte disponível no GitHub .

Edit : Existe um novo livro que sai dos Programmers Pragmáticos que aborda especificamente o código C do teste unitário que Eu recomendo .

152
mikelong

Minunit é um framework de testes unitários incrivelmente simples. Eu estou usando isso para teste de unidade c código do microcontrolador para avr.

128
Matteo Caprari

Atualmente estou usando o framework de teste unitário do CuTest:

http://cutest.sourceforge.net/

É ideal para sistemas embarcados, pois é muito leve e simples. Não tive problemas em fazer com que funcionasse na plataforma de destino, assim como na área de trabalho. Além de escrever os testes de unidade, tudo o que é necessário é:

  • um arquivo de cabeçalho incluído onde quer que você esteja chamando as rotinas do CuTest
  • um único arquivo 'C' adicional a ser compilado/vinculado à imagem
  • algum código simples adicionado ao principal para configurar e chamar os testes de unidade - eu só tenho isso em uma função especial main () que é compilada se UNITTEST é definido durante a construção.

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

Com algum uso criterioso de blocos externos "C" {} ele também suporta testar C++ muito bem.

40
Michael Burr

Eu digo quase o mesmo que ratkok, mas se você tem um toque embutido nos testes de unidade, então ...

nity - Estrutura altamente recomendada para o código C de teste unitário.

Os exemplos no livro mencionados neste thread TDD para C incorporado são escritos usando Unity (e CppUTest).

36
Johan

Você também pode querer dar uma olhada em libtap , uma estrutura de teste C que produz o protocolo TIA (Test Anything Protocol) e, portanto, integra-se bem com uma variedade de ferramentas que estão sendo lançadas para esta tecnologia. É usado principalmente no mundo da linguagem dinâmica, mas é fácil de usar e se tornar 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();
}
32
Ovid

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

Ele também tem suporte para diferentes formatos de saída de mensagem, como Subunit, Test Anything Protocol e jUnit XML reports.

o cmocka foi criado para funcionar também em plataformas embarcadas e também possui suporte ao 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 sobre LWN.net: Teste unitário com objetos simulados em C

o cmocka 1.0 foi lançado em fevereiro de 2015.

26
asn

Eu não cheguei muito longe testando um aplicativo C legado antes de começar a procurar uma maneira de simular funções. Eu precisava muito de zombarias para isolar o arquivo C que quero testar dos outros. Dei uma chance ao cmock e acho que vou adotá-lo.

O Cmock verifica arquivos de cabeçalho e gera funções simuladas com base nos protótipos encontrados. Mocks permitirá que você teste um arquivo C em perfeito isolamento. Tudo o que você precisa fazer é vincular seu arquivo de teste a simuladores em vez de seus arquivos de objetos reais.

Outra vantagem do cmock é que ele validará os parâmetros passados ​​para as funções escarnecidas, e permitirá que você especifique qual valor de retorno os mocks devem fornecer. Isso é muito útil para testar diferentes fluxos de execução em suas funções.

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

O último passo é gerar um corredor para seus testes com unidade. O Cmock está vinculado à estrutura de teste de unidade. A unidade é 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 é a Cmockery.

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

É um framework C puro que suporta testes unitários e zombarias. Não tem dependência do Ruby (ao contrário do Cmock) e tem pouca dependência de bibliotecas externas.

Isso requer um pouco mais de trabalho manual para configurar os mocks porque não gera código. Isso não representa muito trabalho para um projeto já existente, já que os protótipos não mudam muito: assim que você tiver seus mocks, você não precisará mudá-los por um tempo (esse é o meu caso). Tipagem extra fornece controle completo de zombarias. Se há algo que você não gosta, simplesmente mude o seu mock.

Não há necessidade de um corredor de teste especial. Você só precisa criar um array de testes e passá-lo para uma função run_tests. Um pouco mais de trabalho manual aqui também, mas definitivamente gosto da ideia de um framework autônomo independente.

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

No geral, a Cmockery precisa de um pouco mais de entendimento sobre os mocks para começar. Exemplos devem ajudá-lo a superar isso. Parece que pode fazer o trabalho com mecânica mais simples.

20
Philippe A.

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

15
chelmertz

Eu não uso um framework, eu apenas uso o autotools "check". Implemente um "main" e use assert (s).

Meu dir 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
12
navicore

CUnit

E Embedded Unit é uma estrutura de teste unitário para o Sistema C Embarcado. Seu design foi copiado do JUnit e CUnit e mais, e depois adaptado para o Embedded C System. A Embedded Unit não requer bibliotecas padrão. Todos os objetos são alocados para a área const.

E Tessy automatiza o teste unitário do software embarcado.

12
prakash

Nós escrevemos CHEAT (hospedado em GitHub ) para facilidade de uso e portabilidade.

Não tem 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 cuida da execução dos testes e relata seus resultados.

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

Tem cores bonitas também.

12
Tuplanolla

O livro de Michael Feather, "Trabalhando Efetivamente com o Código Legado", apresenta muitas técnicas específicas para testes unitários durante o desenvolvimento do C.

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

11
Frank Schwieterman

CppUTest - Estrutura altamente recomendada para o código C de teste unitário.

Os exemplos no livro que são mencionados neste thread TDD para C incorporado são escritos usando CppUTest.

7
ratkok

além do meu viés óbvio

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

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

6
Keith Nicholas

Eu uso CxxTest para um ambiente c/c ++ incorporado (principalmente C++).

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

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

Guia do Usuário CxxTestWiki CxxTest

6
Zing-

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

5
Roberto Vargas Caballero

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

E sim, até onde eu vejo, ele funcionará com C simples, ou seja, não requer recursos de C++ (pode exigir o compilador C++, não tenho certeza).

4
Paweł Hajdan
4
Landon Kuhn

Cmockery é um projeto recém-lançado que consiste em um simples uso da biblioteca C para escrever testes unitários.

4
Alejandro Bologna

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

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

3
Kevin
2
Tony Bai

API Sanity Checker - framework de teste para bibliotecas C/C++:

Um gerador automático de testes unitários básicos para uma biblioteca compartilhada C/C++. Ele é capaz de gerar dados de entrada razoáveis ​​(na maioria dos casos, mas infelizmente não todos) para parâmetros e compor casos de teste simples ("sanidade" ou "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 criar e executar testes gerados e detectar falhas (segfaults), anulações, todos os tipos de sinais emitidos, código de retorno do programa diferente de zero e suspensão de programas.

Exemplos:

2
linuxbuild

Eu usei RCUNIT para fazer algum teste de unidade para código embutido no PC antes de testar no alvo. Uma boa abstração de interface de hardware é importante, caso contrário, os registros de endianness e mapeamento de memória vão matar você.

2
Gerhard

Se você está familiarizado com o JUnit, então eu recomendo o CppUnit. http://cppunit.sourceforge.net/cppunit-wiki

Isso é supondo que você tenha o compilador c ++ para fazer os testes unitários. se não, então eu tenho que concordar com Adam Rosenfield que cheque é o que você quer.

2
Kwondri

O LibU ( http://koanlogic.com/lib ) possui um módulo de teste unitário que permite dependências explícitas de conjuntos de testes/casos, isolamento de testes, execução paralela e um formatador de relatórios 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 ...

1
bongo

Estou surpreso que ninguém mencionou Cutter (http://cutter.sourceforge.net/) Você pode testar C e C + +, ele se integra perfeitamente com autotools e tem um tutorial muito bom disponível.

1
Kris

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

Certifique-se de compilar regularmente seu código-fonte C em seu compilador cruzado, automaticamente com os testes de unidade, se possível.

1
quamrana

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

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

0
Dushara

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

0
Johannes Passing

Acabei de escrever Libcut por frustração com as bibliotecas de teste de unidades C existentes. Ele possui uma cadeia de tipos automáticos de primitivos (sem necessidade de test_eq_int, test_eq_long, test_eq_short, etc ...; apenas dois conjuntos diferentes para primitivas e cadeias de caracteres) e consiste em um arquivo de cabeçalho. Aqui está um pequeno exemplo:

#include <libcut.h>

LIBCUT_TEST(test_abc) {
    LIBCUT_TEST_EQ(1, 1);
    LIBCUT_TEST_NE(1, 0);
    LIBCUT_TEST_STREQ("abc", "abc");
    LIBCUT_TEST_STRNE("abc", "def");
}

LIBCUT_MAIN(test_abc);

Funciona apenas com o C11.

0
kirbyfan64sos