Хтось робить "справжній" TDD з Visual-C ++, і якщо так, то як це робити? [зачинено]


10

Тестова розробка передбачає написання тесту перед кодом та наступний певний цикл :

  • Тест з написання
  • Перевірка тесту (запустіть)
  • Напишіть виробничий код
  • Перевірка тесту (запустіть)
  • Очистити виробничий код
  • Перевірка тесту (виконання)

Що стосується мене, це можливо лише в тому випадку, якщо ваше рішення для розробки дозволяє дуже швидко перемикатися між виробничим і тестовим кодом і надзвичайно швидко виконати тест для певної частини виробничого коду.

Тепер, хоча існує багато фреймворків тестування модулів для C ++ (я використовую Bost.Test atm.), Схоже, насправді не існує пристойного (для рідного C ++ ) рішення Visual Studio (Plugin), яке робить TDD цикл можна носити незалежно від використовуваної рамки.

"Bearable" означає, що це дія одним клацанням миші для запуску тесту для певного файлу cpp без необхідності вручну встановлювати окремий проект тестування тощо. "Bearable" також означає, що простий тест починається (пов'язує!) І працює дуже швидко .

Отже, які інструменти (плагіни) та методи існують там, що роблять цикл TDD можливим для власного розвитку C ++ за допомогою Visual Studio?

Примітка: я добре вживаю безкоштовні або "комерційні" інструменти.

Будь ласка : Немає рамкових рекомендацій. (Якщо рамка не має спеціального плагіна Visual Studio і ви хочете порекомендувати плагін.)


Редагування Примітка : На сьогодні відповіді містять посилання про те, як інтегрувати блок тестування модулів у Visual Studio. Ресурси більш-менш описують, як змусити структуру UT складати та запускати свої перші тести. Це НЕ то , що це питання о. Я вважаю, що дійсно продуктивно працювати, маючи Unit Tests в ручному режимі (!), Окремий vcproj від ваших виробничих класів додасть стільки накладних витрат, що TDD "неможливо". Наскільки мені відомо, ви не додаєте зайвих "проектів" до Java або C #, щоб увімкнути Unit Tests і TDD, і це не є вагомою причиною. Це повинно бути можливо, за допомогою потрібних інструментів C ++, але здається, що (це питання про те), що інструментів для TDD / C ++ / VS дуже мало.


Гулячи навколо, я знайшов один інструмент, VisualAssert , який, здається, спрямований у правильному напрямку. Однак, afaiks, схоже, він не знайшов широкого застосування (порівняно з CppUnit, Boost.Test тощо).


Редагувати: Я хотів би додати коментар до контексту цього питання. Я думаю, що це добре підсумовує викладення (частину) проблеми: (коментар Біллі ONeal )

Visual Studio не використовує "сценарії побудови", які можна редагувати користувачем. Один проект виробляє один двійковий. Більше того, у Java є властивість, що Java ніколи не будує повного бінарного файлу - бінарний файл, який ви будуєте, - це лише ZIP-файл файлів класу. Тому можна скласти окремо, тоді JAR разом вручну (використовуючи, наприклад, 7z). C ++ і C # насправді пов'язують свої двійкові файли, тому загалом кажучи, ви не можете написати такий сценарій. Найближче до вас може скласти все окремо, а потім зробити два зв’язування (одне для виробництва, а одне для тестування).


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,<- Я не думаю, що це правильно. У вас також зазвичай є кілька проектів і в C #; ви не хочете відправляти свій тестовий код у виробничий двійковий файл.
Біллі ONeal

2
Я ніколи не бачив, щоб це оброблялося рамками. Генерація двійкового файлу вимагає проекту. Ви хочете два бінарні файли; один з тестовим кодом і один з виробничим кодом. Тому вам потрібні два проекти. Навколо цього немає способу.
Біллі ONeal

1
@BillyONeal, у всіх моїх (Java) проектах проект містить головне і тестове джерело - сценарій збірки вибирає, які фрагменти потрібно розмістити в артефакти, що розгортаються.
Роберт Марк Брам

2
@Robert: Visual Studio не використовує "сценарії побудови", які можна редагувати користувачем. Один проект виробляє один двійковий. Більше того, у Java є властивість, що Java ніколи не будує повного бінарного файлу - бінарний файл, який ви будуєте, - це лише ZIP-файл файлів класу. Тому можна скласти окремо, тоді JAR разом вручну (використовуючи, наприклад 7z). C ++ і C # насправді пов'язують свої двійкові файли, тому загалом кажучи, ви не можете написати такий сценарій. Найближче до вас може скласти все окремо, а потім зробити два зв’язування (одне для виробництва, а одне для тестування).
Біллі ONeal

4
Серйозно? "Порада. Кожен тест повинен містити одну основну функцію та генерувати одну виконувану." Це звучить смішно повільно для будь-якої розумної кількості тестів. Навіть якщо вони мають на увазі лише один тестовий пристрій на виконуваний файл, його все ще нерозумне поради IMO. Спробуйте зробити це з тисячами тестів (для середнього проекту) або сотнями тисяч тестів (для великого проекту), і ви, безумовно, зійдете з розуму.
легалізувати

Відповіді:


4

Я написав 5-частинну серію блогу про те, як робити TDD з C ++ та Visual Studio: частина 1 , частина 2 , частина 3 , частина 4 , частина 5 .

Я не впевнений, чому ви говорите, що ви не робите зайвих проектів в C #, щоб робити TDD, тому що це я завжди робив з NUnit, і це здається типовим для інших людей, які також роблять з NUnit. Причина проста: завжди тримайте код тесту окремо від виробничого коду. Для C ++ з Visual Studio це означає окремі проекти, як і для C # і NUnit. З того, що я знаю про світ Java, це теж є загальним.

Очевидно, у кожного є різні уявлення про те, що "терпимо" для ведення TDD. Я практикую метод, який я викладаю у своєму дописі в блозі протягом суворих років, і вважаю це дуже терплячим. C ++ - це мова, що складається на компіляції, і компілювання матеріалів може бути повільним, коли система, що перевіряється, сильно поєднана. Просто немає жодного відходу від цього без рефакторингу на більш вільно поєднаний дизайн.

Моя "дія одним натисканням кнопки" - "Збірка рішення". Якщо ця будівля надто велика, ви завжди можете вивантажувати нерелевантні проекти під час роботи, а потім Build Solution створюватиме лише мінімальний набір проектів, необхідних для оновлення в результаті змін.

Зрозуміло, що характер компіляції часу C ++ робить це забирати трохи більше часу в кожному циклі процесу TDD, ніж це було для NUnit та C #, але впевненість, яку я отримую від мого добре перевіреного коду C ++, того варта. Інакше я буду витрачати набагато більше часу на відладчику. Я б застеріг бути щадним у використанні gmock, оскільки це може суттєво додати час перевірки компіляції. Я поки що в основному отримував легкі "підроблені" предмети і рідко потребував повноцінного функціоналу знущань. Смішні рамки для C ++ базуються на шаблонах, і це може значно збільшити час компіляції, тому їх слід зарезервувати там, де вам справді потрібен макет, і підробка просто не зробить.

Я розглядав можливість створення майстра тестового проекту Boost.Test для автоматизації деякого характеру пластини котла для створення тестового проекту для виробничого коду, але після того, як ви зробите це в кілька разів, це дійсно не так складно зробити вручну.

Що стосується рішень з багатьма (150?) Проектами, є й способи впоратися з цим. Одне з очевидних - знайти групи пов'язаних проектів і зв'язати їх разом і почати використовувати їх / публікувати їх як одиницю. Якщо вам дійсно потрібно відновити / доторкнутися до всіх 150 проектів для невеликих змін, які ви вносите під час циклу TDD, ваш код все одно настільки сильно зв'язаний, що одиничні тести, ймовірно, не принесуть великої різниці.

Переглядаючи посилання IDE netbeans, я виявляю, що цукерка має те, що аналізує вихідний тест і показує невеликий тестовий рядок у вікні із зеленим або червоним символом поруч із ним, що я думав, що пропущу, що прийшов з NUnit, але насправді не сумував. Мені здалося, що для збірки більш корисним є просто провал, і тоді я міг двічі клацнути у вікні помилок, щоб розмістити курсор у місці невдалого твердження.


"... не впевнений, чому ти кажеш, що ти не робиш зайвих проектів у C # ... З того, що я знаю про світ Java, це теж часто зустрічається ..." Можливо, з мого боку виникли помилкові уявлення. (Щонайменше для .NET, тому що вам потрібен виконуваний файл для .NET - для Java вам просто потрібні файли класів, тому я не зовсім бачу, куди би вписався додатковий проект.)
Мартін Бай

Я не впевнений, як Java працює з проектами; Я маю там обмежений досвід. З того, що мало що я знаю, я розумію, що проекти є артефактом ІДЕ, а не мовою. (Строго кажучи, це також стосується C #, але я не знаю нікого, хто просто використовує компілятор командного рядка для чогось іншого, крім коротких статей у блозі чи демонстрацій.) Однак, навіть у Java ви обов'язково тримаєте тестовий код окремим від виробничий код, який саме для вас роблять окремі проекти. Я ніколи не рекомендую умовно компілювати C ++, щоб розділити виробничий та тестовий код.
легалізувати

1
"тримайте тестовий код окремо від виробничого коду. Це те, що окремі проекти роблять для вас" - ага! Ну не дуже, ІМХО. Окремий "проект" є необхідністю для C ++ та .NET, оскільки обом потрібно створити виконуваний файл, щоб запустити що завгодно, і створити (один) виконуваний файл, вам потрібен (один) проект. Я добре тримаю тестовий код від (або не) від виробничого коду, але мені здається, що потрібно додати (зайвий) "проект", щоб генерувати тестовий виконуваний файл. :-)
Мартін

1
Вам потрібні два вбудовані продукти: виробничий код (статична бібліотека, спільна бібліотека, виконуваний файл тощо) та тестовий виконуваний файл. У Visual Studio кожен вбудований продукт відповідає проекту, тому вам потрібно два проекти. Це насправді не складніше за це. Тестовий проект одиниці НЕ є зайвим.
легалізувати

2

Я не використовую Visual-C ++, але я виконую TDD з C ++, використовуючи googletest та googlemock, з QtCreator як IDE. Роки тому в мене було подібне налаштування з Visual-C ++, але я використовував інший блок тестування.

Що мені здалося корисним - це розділити проект на кілька підпроектів.

  1. Статична або динамічна бібліотека, яка містить 99% фактичного вихідного коду проекту.
  2. Проект, який складається здебільшого з основного () методу для запуску звичайної програми.
  3. Тестовий проект, який містить main () для запуску моєї тестової рамки та безліч файлів, що містять тести та макети об’єктів.

За допомогою цієї установки мій IDE піклується про додавання файлів до різних проектів, і якщо правильно визначаються залежності, я можу запустити всі мої тести з частковою перебудовою. У мене навіть є налаштування для запуску всіх моїх тестів одразу після створення. Дженкінс, ІС, який я зараз використовую, також працює і надає результати тестів та дані про покриття.

Можливо, можливо, додати в свій IDE користувальницький запуск для файлу для запуску одиничних тестів для файлу Foo.cpp, якщо ви випадково назвали всі одиничні тести для Foo під тестовим кріпленням TestFoo. Як налаштувати це саме для Visual-C ++ Я не впевнений, але я думаю, що це можливо.


Корисна інформація, хоча я б ішов так далеко, щоб назвати це "загальною порадою" :-) ... також це не реально для наших спадщин, але додавання тестів до спадщини - це все одно біль ( і я хотів би хоч трохи спростити додавання тестової установки).
Мартін Ба

2

Я використовую MSTest для тестування нативного C ++ коду.
Ось чудовий пост у цьому блозі: http://blogs.msdn.com/b/jsocha/archive/2010/11/19/writing-unit-tests-in-visual-studio-for-native-c. асп

Так, буде щонайменше два проекти - один для самої заявки, один для тестів.
Замість того, щоб робити третій проект зі статичною бібліотекою, я просто додаю джерело програми до тестового проекту, тому рішення виглядає так:

[-] 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

Я вважаю, що використання C ++ / CLI матеріалів для тестування одиниць просто замулює води при тестуванні чистого кодового коду С ++. Однак я використовував NUnit для тестування коду програми C ++ / CLI. Я написав свої тести на C #, і це спрацювало чудово. (Існуюча база коду була C ++ / CLI, і я не хотів її портувати на C #.)
легалізуйте

Крім того, якщо ваші тести знаходяться в C ++ / CLI, ви не можете запустити їх на інших платформах. Більшість місць, де я використовував C ++, їм потрібна була можливість компіляції між платформами. Звичайно, ви не можете повторно використовувати проект VS на інших платформах, але для нього не так складно мати Makefiles або SConscripts.
легалізувати

@legalize Ми також не можемо повторно використовувати WinAPI (а також COM та інші Windows-технології) на інших платформах Windows.
Абікс

Так, звичайно, ви не можете використовувати конкретні технології Windows на платформах, які не є Windows. Моє спостереження полягало в тому, що якщо у вас є агностичний код платформи, ви не хочете прив'язувати свої одиничні тести до певної платформи. У попереднього роботодавця ми використали велику кількість одиниць тестових рамок і методів. Ми вибрали Boost.Test, оскільки це була крос-платформа, і якщо що-небудь коли-небудь потрапить у стандартну бібліотеку C ++ щодо тестування одиниць, це, швидше за все, буде Boost.Test.
легалізувати

2

Можливо, трохи пізно вдень, але якщо я правильно прочитав ваше запитання, ви шукаєте методи для покращення циклу TDD? Тут не згадувалося, але ви подивилися на події після побудови у VS?

Наші рішення зазвичай організовані (із показаними залежностями проекту) ...

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

Подія після складання MAIN-APP запустить UNIT-TEST-APP

Подія після складання UNIT-TEST-APP запуститься сама (просто поставте "$ (TargetPath)" як команду для запуску в події після складання).

(Це означає, що при побудові MAIN-APP модульні тести можуть виконуватися двічі, але це насправді не було проблемою в нашому випадку!)

Як уже згадувалося, так, для створення цієї структури докладено трохи зусиль, але як тільки вона є, додавання тестів просте.

Отже, все, що вам потрібно зробити, - це створити основне додаток, і тести для одиниць будуть запускатися автоматично!


1

Ну, не знаю, чи це допомагає, але є кілька чудових відео про TDD від Brett L. Schuchert. На жаль, він не показує поєднання "C ++" та "VS", але

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

TDD з C ++ та Eclipse: http://vimeo.com/13240481

Можливо, ви зможете це випрацювати з цих двох.

EDIT: Звичайно, відео C ++ стосується використання тестування фреймворків CppUTest з Eclipse, звичайно. Коли я опублікував це, я подумав, що його слід легко прийняти для використання у VS. Тож я трохи погуглив і виявив таке:

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

яка дає вам інформацію про те, як користуватися CppUTest у Visual Studio.


2
Док. - Я (тільки) подивився відео TDD / Eclipse, але я оскаржую це. Відео точно показує те, що мене не цікавить, а саме як написати код Unit Test. Проблема (у цьому питанні) полягає не в написанні модульних тестів, а в тому, як правильно їх інтегрувати у свою виробничу розробку C ++, і я не бачу, як ці відео допомагають тут.
Мартін Ба

Хоча я відповідав цій відповіді в контексті цього питання, я хотів би додати, що відео дуже приємні. Я вважав Eclipse / TDD / C ++ цікавим для перегляду. Тут просто не допомагає :-)
Martin Ba

@Martin: дивись мою редакцію.
Doc Brown

Ваші зусилля оцінені, і хоча я не думаю, що ця додаткова посилання справді корисна в контексті цього питання, я думаю, що мені потрібно буде зробити кілька редагувань.
Мартін Ба

@Martin: гаразд, я знову прочитав ваше запитання та ваше визначення "терпімості", але ви не очікуєте, що занадто багато? Створення проекту тестування одиниць не є рішенням "одним клацанням миші", але зусилля, щоб написати фактичні одиничні тести, переважають, ніж на порядки, залежно від того, яку структуру ви використовуєте.
Doc Brown

1

Googletest
Як інтегрувати з VC ++

Вам не потрібен плагін, тест - це ще одна ціль. Немає плагінів, щоб генерувати тест на c ++, evne, якщо ви могли б, це тестування безглуздих матеріалів, таких як завдання


"навіть якщо ви могли б це тестувати безглузді речі, такі як завдання" - що це повинно означати? Ви дійсно вважаєте, що краща підтримка IDE для Unit Tests на C ++ марна ??
Мартін Ба

Я маю на увазі на такій мові, як c ++, система не може автоматично створювати тести для нічого іншого, крім очевидних тверджень
Мартін Бекетт

2
Чому ні? Що перешкоджає плагіну автоматично генерувати vcprojфайл на льоту, втягуючи в нього тестовий файл, який я написав, і виробничий файл, на який посилаються, і намагається запустити це? (Тільки мрію, але це могло б змусити працювати.)
Мартін Бала

2
Я не впевнений, що можу наслідувати. очевидно, я повинен сам писати Тести . Але запуск їх може бути набагато простішим, що доведеться вручну налаштовувати (і підтримувати!) Окремі файли тестових проектів.
Мартін Ба

2
Ні, я не посилався на тестовий код, а скоріше на проектні / компіляторні риштування, необхідні для отримання тестового коду плюс «це» виробничий код для запуску.
Мартін Ба

1

Не можу коментувати інструменти C ++, оскільки я не торкався приблизно 20 років (.NET Dev в ці дні), і, мабуть, більшість інструментів у ці дні призначені для керованого коду, але щодо техніки ...

Як уже згадували інші, тестовий код завжди є зовсім іншим проектом / складанням, ніж виробничий код, і так, зазвичай, вам доведеться підтримувати цей проект самостійно, хоча, безумовно, у VS IDE це не велика проблема, оскільки у вас часто є кілька проектів, оскільки частина вашого рішення все одно.

Виробничий код є і повинен бути написаний дещо іншим для TDD. Під час написання тестів спершу вам доведеться спроектувати код, який можна перевірити. Це сама інша тема сама по собі, але це може зайняти час і здається дуже неприємним спочатку, особливо якщо ваші IDE / інструменти не дають вам швидкого зворотного зв’язку, обстріл для запуску інструментів командного рядка для запуску тестів просто руйнівний.

Існує безліч специфічних прийомів для того, щоб зробити код перевіряючим, але більшість з них розбиваються на створення невеликих об'єктів, які не роблять багато, так що ви можете перевірити їх ізольовано і мати можливість ввести тестову версію певної поведінки в більш складну об’єкти. Тут можуть багато допомогти рамки МОК.

Книга, яка вам може бути корисною, є; Майкл Перо, Ефективно працюючи зі спадковим кодексом. Це використовує кілька мов у своїх прикладах і може допомогти вам визначити конкретні підходи до безпечної адаптації коду / методи, які спочатку не були розроблені для перевірки.

Невеликий застереження: я п’яний від Agile Kool-Aid років тому: D


Примітка: я вже маю Working Effectively with Legacy Codeна своєму столі :-)
Мартін

0

Maven не використовується широко в C ++ (все-таки він використовується в основному для Java, але є мовним агностиком), але це дуже потужний інструмент і дозволяє зберігати все в одному проекті (включаючи тести, насправді, це рекомендується підхід з Мейвен). Я пропоную це лише зараз, оскільки з відповідей поки що виглядає альтернатива плагіну VS, можливо, не існує.

Пошук плагінів я знайшов:

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

але, схоже, це ще не дуже зріло. З настройкою Maven все, що вам потрібно зробити для запуску тестів, виконується mvn testв командному рядку.

Якщо ви зацікавлені, ви можете дізнатися про це тут і (один із) підтримуючих плагінів C ++ тут (Maven має архітектуру плагінів, тому все є плагіном).


0

Рамкова рекомендація: У нашому офісі ми використовуємо TestDriven.NET, який інтегрується з Visual Studio. Класи одиничних тестів записуються на C ++ / CLI, який потім може викликати будь-який нативний код, який потрібно перевірити. Так, класи C ++ / CLI переходять у власну збірку, таким чином проект (и) тестування додається до рішення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.