Módulo de Teste de Unidade - Funções Internas

5

Estou escrevendo um conjunto de testes de unidade whitebox simples para um projeto no qual estou trabalhando C. O projeto é dividido em módulos (cada um tem um arquivo .c com um arquivo .h associado) e todos os módulos são compilados juntos em um arquivo .so .

Obviamente, o arquivo .h para cada módulo contém protótipos de função para qualquer função que seja visível para os outros módulos, mas não contém protótipos para funções internas ou auxiliares.

Meu conjunto de testes é uma coleção de arquivos .c em um diretório separado. Cada arquivo .c é responsável por testar um módulo específico, além de um arquivo mestre que executa todos os testes. Todos esses arquivos são compilados em um executável. Atualmente, esse binário está vinculado ao binário .so do projeto e estou #include dos arquivos .h do projeto nos arquivos de teste de módulo individuais, conforme apropriado. Isso me permite testar todas as funções "públicas".

Eu também gostaria de testar diretamente algumas das funções internas e auxiliares. Eu posso pensar em algumas maneiras de fazer isso.

  1. Vá em frente e faça todas as funções de um módulo definidas no arquivo de cabeçalho desse módulo. Eu não quero fazer isso porque parece uma má prática.
  2. Crie uma segunda coleção de arquivos .h que contenham os protótipos de todas as funções internas / auxiliares e inclua-os nos arquivos de teste apropriados. Eu hesito em fazer isso porque parece muito trabalho para manter.
  3. #include do arquivo .c do módulo diretamente. Isso seria fácil de manter, mas me faria sentir tão sujo por dentro.

Quais (se houver) dessas técnicas são a melhor maneira de fazer isso?

    
por Woodrow Barlow 02.02.2016 / 17:59
fonte

3 respostas

2

Você considerou colocar as funções no arquivo de cabeçalho do módulo, mas colocá-las em um bloco compilado condicionalmente que só é habilitado em configurações de compilação que são testadas? Seria análogo ter uma classe C ++ com funções públicas e privadas. No entanto, essa não é uma boa opção se você enviar o arquivo de cabeçalho aos usuários e quiser manter essas funções em segredo.

Incluir o arquivo C diretamente é uma opção muito suja, pois ele pode não ser construído exatamente da mesma forma que no código "real" e também pode causar problemas de compilação quando as funções que estão no cabeçalho são implementadas múltiplas vezes (na biblioteca e no código de teste). Dito isso, eu recorri a fazer essas coisas às vezes. Quando as coisas não são projetadas para serem testadas desde o começo, às vezes você precisa se sujar um pouco.

    
por 03.02.2016 / 19:42
fonte
5

Os testes de unidade devem ser apenas para funções externas.

No entanto, se você tem um monte de "código interno", ele deve ser testado também, certo? Então, como?

Faça funções menores, separadas do seu código (outro .c e .h), e use essas funções como uma biblioteca que pode ser testada na unidade. Então você deve ser capaz de testar as funções que são usadas pelas internas da API externa sem nenhum problema. O que você não pode testar é como você usa essas funções. Mas o comportamento dessas funções deve causar algo que possa ser testado nas funções externas, caso contrário, por que elas estão lá?

Isso é fácil de manter. Uma dor para fazer isso se você tiver muito código já escrito, mas factível.

    
por 03.02.2016 / 10:07
fonte
0

A coisa com qualquer forma de teste é que, para que valha a pena, quando encontra defeitos, você precisa consertá-los. Embora seja muito fácil, em vez disso, alterar seus testes para que correspondam ao comportamento de bugs, isso invalida todo o exercício.

Nesse caso, seu teste encontrou defeitos: suas funções internas têm caminhos que não podem ser acessados por testes da API externa. Talvez eles sejam apenas verificações de nulos redundantes, talvez você esteja perdendo alguns casos de teste de nível mais alto, talvez a lógica interna implemente uma abstração mais geral do que realmente usada.

De qualquer forma, a abordagem correta é corrigi-los. Verificações nulas que não podem acionar devem ser asserções (que devem ser excluídas da cobertura de código), casos de teste ausentes devem ser gravados, abstrações internas devem estar em seu próprio arquivo.

    
por 04.02.2016 / 13:54
fonte