Alguém está fazendo TDD "real" com Visual-C ++ e, se sim, como eles fazem isso? [fechadas]


10

O Desenvolvimento Orientado a Testes implica escrever o teste antes do código e seguir um certo ciclo :

  • Teste de gravação
  • Verificar teste (execução)
  • Escrever código de produção
  • Verificar teste (execução)
  • Limpar código de produção
  • Teste de verificação (execução)

Para mim, isso só é possível se sua solução de desenvolvimento permitir alternar muito rapidamente entre o código de produção e teste e executar o teste para uma determinada parte do código de produção com extrema rapidez.

Agora, enquanto existem muitas estruturas de teste de unidade para C ++ (estou usando o atm Bost.Test), parece que realmente não existe nenhuma solução decente (para C ++ nativa ) do Visual Studio (Plugin) que faça o TDD ciclo suportável, independentemente da estrutura usada.

"Suportável" significa que é uma ação de um clique executar um teste para um determinado arquivo cpp sem ter que configurar manualmente um projeto de teste separado etc. "Suportável" também significa que um teste simples é iniciado (vinculado!) E executado muito rapidamente .

Então, quais ferramentas (plug-ins) e técnicas existem para tornar o ciclo TDD possível para o desenvolvimento nativo de C ++ com o Visual Studio?

Nota: Eu estou bem com ferramentas gratuitas ou "comerciais".

Por favor : Não há recomendações de estrutura. (A menos que a estrutura tenha um plug-in Visual Studio dedicado e você queira recomendar o plug-in.)


Nota de edição : As respostas até o momento forneceram links sobre como integrar uma estrutura de Teste de Unidade ao Visual Studio. Os recursos descrevem mais ou menos como obter a estrutura do UT para compilar e executar seus primeiros testes. Isso é não o que esta pergunta é sobre. Sou da opinião de que, para realmente trabalhar produtivamente, tendo os Testes de Unidade em uma manutenção manual (!), Separar vcproj de suas classes de produção adicionará tanta sobrecarga que o TDD "não é possível". Tanto quanto sei, você não adiciona "projetos" extras a uma coisa Java ou C # para habilitar testes de unidade e TDD, e por um bom motivo. Isso deveria possível com o C ++, dadas as ferramentas corretas, mas parece (essa pergunta é sobre) que existem muito poucas ferramentas para TDD / C ++ / VS.


Pesquisando, encontrei uma ferramenta, o VisualAssert , que parece apontar na direção certa. No entanto, em geral, não parece ser amplamente utilizado (comparado ao CppUnit, Boost.Test etc.).


Editar: eu gostaria de adicionar um comentário ao contexto desta pergunta. Eu acho que ele faz um bom resumo do esboço (parte) do problema: (comentário por Billy ONeal )

O Visual Studio não usa "scripts de criação" razoavelmente editáveis ​​pelo usuário. Um projeto produz um binário. Além disso, o Java tem a propriedade de que o Java nunca constrói um binário completo - o binário que você constrói é apenas um ZIP dos arquivos de classe. Portanto, é possível compilar separadamente e JAR juntos manualmente (usando, por exemplo, 7z). C ++ e C #, na verdade, vinculam seus binários, de modo geral, você não pode escrever um script como esse. O mais próximo que você pode chegar é compilar tudo separadamente e, em seguida, fazer dois vínculos (um para produção e outro para teste).


2
As far as I am aware, you do not add extra "projects" to a Java or C# thing to enable Unit Tests and TDD,<- Não acho que isso esteja correto. Você também costuma ter vários projetos em C #; você não deseja enviar seu código de teste no seu binário de produção.
Billy ONeal

2
Eu nunca vi isso tratado pela estrutura. A geração de um binário requer um projeto. Você quer dois binários; um com código de teste e outro com código de produção. Portanto, você precisa de dois projetos. Não há maneira de contornar isso.
Billy ONeal

11
@BillyONeal, em todos os meus projetos, exceto em um (Java), o projeto contém a fonte principal e de teste - o script de construção seleciona as peças a serem inseridas nos artefatos implementáveis.
Robert Mark Bram

2
@ Robert: O Visual Studio não usa "scripts de compilação" razoavelmente editáveis ​​pelo usuário. Um projeto produz um binário. Além disso, o Java tem a propriedade de que o Java nunca constrói um binário completo - o binário que você constrói é apenas um ZIP dos arquivos de classe. Portanto, é possível compilar separadamente e, em seguida, JAR juntos manualmente (usando, por exemplo 7z). C ++ e C #, na verdade, vinculam seus binários, de modo geral, você não pode escrever um script como esse. O mais próximo que você pode chegar é compilar tudo separadamente e, em seguida, fazer dois vínculos (um para produção e outro para teste).
Billy ONeal

4
A sério? "Dica: Cada teste deve conter uma função principal e gerar um executável." Isso soa ridiculamente lento para qualquer quantidade razoável de testes. Mesmo que eles signifiquem apenas um dispositivo de teste por executável, seu conselho ainda é bobo IMO. Tente fazer isso com milhares de testes (para um projeto de tamanho médio) ou centenas de milhares de testes (para um projeto grande) e você definitivamente ficará louco.
legalize

Respostas:


4

Eu escrevi uma série de blogs em 5 partes sobre como fazer TDD com C ++ e Visual Studio: parte 1 , parte 2 , parte 3 , parte 4 , parte 5 .

Não sei por que você diz que não faz projetos extras em C # para fazer TDD, porque é o que eu sempre fiz com o NUnit e parece típico do que outras pessoas fazem com o NUnit também. O motivo é simples: sempre mantenha o código de teste separado do código de produção. Para C ++ com Visual Studio, isso significa projetos separados, assim como para C # e NUnit. Pelo que sei do mundo Java, isso também é comum lá.

Obviamente, todo mundo tem idéias diferentes do que é "suportável" para fazer TDD. Venho praticando o método descrito em meu blog há vários anos e acho muito suportável. C ++ é uma linguagem compilada e o material de compilação pode ser lento quando o sistema em teste é altamente acoplado. Simplesmente não há como fugir disso sem refatorar para um design mais frouxamente acoplado.

Minha "ação de um clique" é "Build Solution". Se estiver construindo demais, você sempre poderá descarregar projetos irrelevantes enquanto estiver trabalhando e o Build Solution criará apenas o subconjunto mínimo de projetos necessários para serem atualizados como resultado de suas alterações.

É verdade que a natureza do tempo de compilação do C ++ demora um pouco mais em cada ciclo do processo TDD do que com o NUnit e o C #, mas vale a confiança que recebo do meu código C ++ bem testado. Caso contrário, passarei muito mais tempo no depurador. Eu recomendaria ser poupador no uso do gmock, pois ele pode aumentar substancialmente o tempo de compilação do teste. Até agora, na maioria das vezes, consegui objetos leves e "falsos" e raramente preciso da funcionalidade completa de zombarias. As estruturas de simulação para C ++ são fortemente baseadas em modelos e isso pode aumentar significativamente o tempo de compilação; portanto, elas devem ser reservadas para onde você realmente precisa de uma simulação e uma farsa simplesmente não funciona.

Eu considerei criar um assistente de projeto de teste de unidade Boost.Test para automatizar parte da natureza da chapa da caldeira de criar o projeto de teste para o código de produção, mas depois de fazer isso algumas vezes, não é tão difícil de fazer manualmente.

Quanto às soluções com muitos projetos (150?), Há maneiras de lidar com isso também. Um exemplo óbvio é encontrar grupos de projetos relacionados, agrupá-los e começar a consumi-los / publicá-los como uma unidade. Se você realmente precisa reconstruir / tocar em todos os 150 projetos para pequenas alterações que você está fazendo durante um ciclo de TDD, seu código é tão altamente acoplado de qualquer maneira que os testes de unidade provavelmente não farão muita diferença.

Olhando para o link IDE do netbeans, acho o colírio para os olhos algo que analisa a saída de teste e mostra uma pequena linha de teste em uma janela com um símbolo verde ou vermelho ao lado, algo que eu pensei que sentiria falta de ter vindo da NUnit, mas na verdade não errou. Achei mais útil a compilação simplesmente falhar e, em seguida, clique duas vezes na janela de erros para colocar o cursor no local da asserção com falha.


"... não sei por que você diz que não faz projetos extras em C # ... Pelo que sei do mundo Java, isso também é comum lá ..." Pode ter sido um equívoco da minha parte. (Pelo menos para o .NET, porque você precisa de um executável para o .NET - para java, você só precisa dos arquivos de classe, por isso não vejo exatamente onde o projeto extra se encaixaria.)
Martin Ba

Não tenho certeza de como o Java funciona com projetos; Eu tenho experiência limitada lá. Pelo pouco que sei, entendo que os projetos são um artefato do IDE e não a linguagem. (Estritamente falando, isso também é verdade para C #, mas não conheço ninguém que apenas use o compilador de linha de comando para outras coisas que não sejam pequenos artigos ou demonstrações de blog.) No entanto, mesmo em Java, você definitivamente mantém o código de teste separado de o código de produção, que é o que projetos separados estão fazendo por você. Eu nunca recomendo compilar condicionalmente C ++ para separar o código de produção e teste.
legalize

11
"mantenha o código de teste separado do código de produção, que é o que projetos separados estão fazendo por você" - aha! Bem, na verdade não, IMHO. O "projeto" separado é uma necessidade para C ++ e .NET, porque ambos precisam criar um executável para executar qualquer coisa e criar um (um) executável, você precisa de um (um) projeto. Estou bem em manter o código de teste separado (ou não) do código de produção, mas acho que é necessário adicionar um "projeto" (redundante) para gerar o executável do teste irritante. :-)
Martin Ba

11
Você precisa de dois produtos criados: código de produção (biblioteca estática, biblioteca compartilhada, executável etc.) e um executável de teste. No Visual Studio, cada produto criado corresponde a um projeto, então você precisa de dois projetos. Realmente não é mais complicado do que isso. O projeto de teste de unidade NÃO é redundante.
legalize

2

Não estou usando Visual-C ++, mas estou executando o TDD com C ++, usando googletest e googlemock, com QtCreator como meu IDE. Anos atrás, eu tinha uma configuração semelhante ao Visual-C ++, mas usando uma estrutura de teste de unidade diferente.

O que eu achei útil é separar o projeto em alguns subprojetos.

  1. Uma biblioteca estática ou dinâmica que contém 99% do código-fonte real do projeto.
  2. Um projeto que consiste principalmente de um método main () para executar o programa normal.
  3. Um projeto de teste que contém um main () para executar minha estrutura de teste e muitos arquivos que contêm testes e objetos simulados.

Com essa configuração, meu IDE cuida de adicionar arquivos a vários projetos e, se as dependências estiverem sendo determinadas corretamente, eu posso executar todos os meus testes de unidade com uma reconstrução parcial. Eu ainda o tenho configurado atualmente para executar todos os meus testes imediatamente após a compilação. Jenkins, o IC que estou usando atualmente, também executa e fornece resultados de testes e dados de cobertura.

Pode ser possível adicionar um iniciador personalizado no seu IDE para um arquivo para executar os testes de unidade do arquivo Foo.cpp se você nomear todos os testes de unidade do Foo no equipamento de teste TestFoo. Como configurar isso precisamente para o Visual-C ++ Não tenho certeza, mas acho que é possível.


Informações úteis, embora eu vá até o ponto de chamá-lo de "conselho comum" :-) ... também não é realmente viável para nosso material herdado, mas adicionar testes ao material herdado é uma dor de qualquer maneira ( e eu gostaria de fazer o mínimo para facilitar a adição do equipamento de teste).
Martin Ba

2

Eu uso o MSTest para testar o código C ++ nativo.
Aqui está o ótimo post sobre este caminho: http://blogs.msdn.com/b/jsocha/archive/2010/11/19/writing-unit-tests-in-visual-studio-for-native-c. aspx

Sim, haverá pelo menos dois projetos - um para o próprio aplicativo, outro para testes.
Em vez de criar um terceiro projeto com biblioteca estática, apenas adiciono a fonte do aplicativo ao projeto de teste, para que a solução fique assim:

[-] Solution 'Foo'      Foo\Foo.sln
 |-[-] Foo              Foo\Foo\Foo.vcproj
 |  |-[-] include
 |  |  |- foo.h         Foo\Foo\foo.h
 |  |  |- bar.h         Foo\Foo\bar.h
 |  |
 |  |-[-] source
 |     |- foo.cpp       Foo\Foo\foo.cpp
 |
 |-[-] Foo.Tests        Foo\Foo.Tests\Foo.Tests.vcproj
    |                        (Additional include directory: "..\Foo")
    |-[-] include
    |  |- FakeBar.h     Foo\Foo.Tests\FakeBar.h
    |
    |-[-] source
       |-[-] app
       |  |- foo.cpp    Foo\Foo\foo.cpp    -- not in Foo.Tests\
       |
       |-[-] unit-tests
          |- foo_Tests.cpp   Foo\Foo.Tests\foo_Tests.cpp
          |- bar_Tests.cpp   Foo\Foo.Tests\bar_Tests.cpp

Acho que usar o material C ++ / CLI para teste de unidade apenas atrapalha as águas ao testar código C ++ nativo puro. No entanto, usei o NUnit para testar o código do aplicativo C ++ / CLI. Eu escrevi meus testes em C # e funcionou muito bem. (A base de código existente era C ++ / CLI e eu não queria portá-la para C #.)
legalize

Além disso, se seus testes estiverem em C ++ / CLI, não será possível executá-los em outras plataformas. Na maioria dos lugares em que usei C ++, eles precisavam da capacidade de compilação entre plataformas. É claro que você não pode reutilizar o projeto VS em outras plataformas, mas não é grande coisa ter Makefiles ou SConscripts para ele.
legalize

@ legalize Não podemos reutilizar o WinAPI (e COM e outras tecnologias específicas do Windows) em plataformas não Windows também.
Abyx

Sim, é claro que você não pode usar tecnologias específicas do Windows em plataformas não Windows. Minha observação foi simplesmente que, se você possui um código independente de plataforma, não deseja vincular seus testes de unidade a uma plataforma específica. Em um empregador anterior, avaliamos um grande número de estruturas e métodos de teste de unidade. Escolhemos o Boost.Test porque era multiplataforma e, se alguma coisa acabasse na biblioteca padrão C ++ em relação a testes de unidade, provavelmente seria o Boost.Test.
legalize

2

Talvez um pouco tarde, mas se eu li sua pergunta corretamente, você está procurando técnicas para melhorar o ciclo TDD? Não foi mencionado aqui, mas você já viu eventos pós-compilação no VS?

Nossas soluções são normalmente organizadas (com as Dependências do projeto mostradas) ...

MAIN-APP > LIB1, LIB2, UNIT-TEST-APP
UNIT-TEST-LIB1 > LIB1
UNIT-TEST-LIB2 > LIB2
UNIT-TEST-APP > UNIT-TEST-LIB1, UNIT-TEST-LIB2

O evento pós-compilação do MAIN-APP executará UNIT-TEST-APP

O evento pós-compilação do UNIT-TEST-APP será executado automaticamente (basta colocar '$ (TargetPath)' como o comando a ser executado no evento pós-compilação).

(Isso significa que, ao criar o APP PRINCIPAL, os testes de unidade podem ser executados duas vezes, mas isso não foi realmente um problema no nosso caso!)

Como mencionado, sim, existe uma pouco de esforço na configuração dessa estrutura, mas, uma vez lá, adicionar testes é simples.

Então, tudo o que você precisa fazer é criar o aplicativo principal e os testes de unidade serão executados automaticamente!


1

Bem, não sei se isso ajuda, mas existem ótimos vídeos sobre TDD de Brett L. Schuchert. Infelizmente, ele não mostra a combinação "C ++" e "VS", mas

TDD com C # e VS: http://vimeo.com/album/210446

TDD com C ++ e Eclipse: http://vimeo.com/13240481

Talvez você possa trabalhar com esses dois.

EDIT: o vídeo C ++ é sobre o uso da estrutura de teste CppUTest com o Eclipse, é claro. Quando publiquei, achei que deveria ser facilmente adotado para uso no VS. Então, pesquisei um pouco e descobri o seguinte:

http://schuchert.wikispaces.com/tdd.cpp.NotesOnCppUTest

que fornece informações sobre como usar o CppUTest no Visual Studio.


2
Doc - Eu (apenas) vi o vídeo TDD / Eclipse, mas vou rebater este. O vídeo mostra exatamente o que não me interessa, como escrever o código do teste de unidade. O problema (desta pergunta) não é escrever testes de unidade, é como integrá- los adequadamente ao seu desenvolvimento de produção em C ++ e não vejo como esses vídeos ajudam aqui.
Martin Ba

Embora tenha diminuído a votação desta resposta no contexto desta pergunta, gostaria de acrescentar que os vídeos são bastante agradáveis. Achei interessante o Eclipse / TDD / C ++. Ele só não ajudar aqui :-)
Martin Ba

@ Martin: veja minha edição.
Doc Brown

Seu esforço é apreciado e, embora eu não ache que esse link adicional seja realmente útil no contexto desta pergunta, acho que vou precisar fazer algumas edições.
Martin Ba

@ Martin: ok, eu li sua pergunta novamente e sua definição de "suportável", mas você não espera um pouco demais? A configuração de um projeto de teste de unidade não é uma solução de "um clique", mas o esforço para escrever os testes de unidade reais supera isso por ordens de magnitude, independentemente da estrutura que você estiver usando.
Doc Brown

1

Googletest
Como integrar com vc ++

Você não precisa de um plugin, o teste é apenas outro alvo. Não há plugins para gerar teste com c ++, mesmo que você pudesse testar coisas inúteis, como atribuições


"mesmo que você pudesse, estaria testando coisas inúteis, como tarefas" - o que isso significa? Você realmente acha que um melhor suporte IDE para testes de unidade em C ++ é inútil?
Martin Ba

Quero dizer, em uma linguagem como c ++, o sistema não pode criar automaticamente testes para outra coisa senão declarações óbvias
Martin Beckett

2
Por que não? O que está impedindo um plug-in de gerar automaticamente um vcprojarquivo em tempo real, puxando o arquivo de teste que eu escrevi e o arquivo de produção referenciado e tentando executá-lo? (Apenas sonhando, mas poderia ser feito para trabalhar.)
Martin Ba

2
Não tenho certeza se posso seguir. obviamente eu tenho que escrever os testes eu mesmo. Mas executá- los pode ser muito mais fácil do que ter que configurar manualmente (e manter!) Separar arquivos de projeto de teste.
Martin Ba

2
Não, não me referi ao código de teste, mas ao andaime do projeto / compilador necessário para obter o código de teste mais o código de produção "it" para execução.
Martin Ba

1

Não posso comentar sobre as ferramentas C ++, pois não falo há 20 anos (.NET dev atualmente) e acho que a maioria das ferramentas atualmente são para código gerenciado, mas para técnicas ...

Como outros já mencionaram, o código de teste está sempre em um projeto / montagem completamente diferente do código de produção e sim, você normalmente precisa manter esse projeto sozinho, embora certamente no VS IDE isso não seja um grande problema, pois muitas vezes você tem vários projetos. parte da sua solução de qualquer maneira.

O código de produção é e deve ser escrito um pouco diferente para TDD. À medida que você escreve os testes, você acaba tendo que projetar seu código para ser testável. Esse é outro assunto em si, mas pode levar tempo e parecer muito frustrante no início, especialmente se suas ferramentas / IDE não fornecerem um feedback rápido, optar por executar ferramentas de linha de comando para executar testes é apenas disruptivo.

Existem muitas técnicas específicas para tornar o código testável, mas a maioria delas se divide em criar objetos pequenos que não fazem muito, para que você possa testá-los isoladamente e poder injetar uma versão de teste de algum comportamento em algo mais complexo. objetos. As estruturas do COI podem ajudar muito aqui.

Um livro que você pode achar útil é; Michael Feathers, trabalhando efetivamente com o Legacy Code. Isso usa vários idiomas em seus exemplos e pode ajudar a identificar abordagens específicas para adaptar com segurança códigos / técnicas que não foram originalmente projetadas para serem testáveis.

Advertência pequena: bebi do Agile Kool-Aid anos atrás: D


Nota: eu já tenho Working Effectively with Legacy Codena minha mesa :-)
Martin Ba

0

O Maven não é amplamente usado em C ++ (ainda é usado principalmente para Java, mas é independente da linguagem), mas é uma ferramenta muito poderosa e permite manter tudo em um único projeto (incluindo testes, de fato, é o recomendado). abordagem com Maven). Só o sugiro agora, já que a partir das respostas até agora parece que uma alternativa com um plug-in do VS pode não existir.

Procurando por plugins que encontrei:

http://incubator.apache.org/npanday/

mas ainda não parece muito maduro. Com a instalação do Maven, tudo o que você precisa fazer para executar os testes é executado mvn testna linha de comando.

Se você estiver interessado, pode aprender sobre isso aqui e (um dos) plugins de suporte a C ++ aqui (o Maven possui uma arquitetura de plugins, então tudo é um plug-in).


0

Recomendação de estrutura: Em nosso escritório, usamos o TestDriven.NET que se integra ao Visual Studio. As classes mais unittest são escritas em C ++ / CLI, que podem ser chamadas para exercitar qualquer código nativo que você precise testar. Sim, as classes C ++ / CLI entram em seu próprio assembly, portanto, um projeto de "teste" foi adicionado à (s) solução (s).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.