Чому тестування мови не підтримується функцією на рівні синтаксису?


37

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

То чому тоді, незважаючи на свою популярність, тестування відсутнє у синтаксисі цих мов?

Microsoft представила LINQ на C # , тому чому вони також не могли додати тестування?

Я не прагну передбачити, якими будуть ці зміни в мові, а щоб уточнити, чому вони відсутні для початку.

Як приклад: Ми знаємо, що ви можете написати forцикл без синтаксису forвисловлювання. Ви можете використовувати whileабо if/ gotoзаяви. Хтось вирішив, що forтвердження є більш ефективним, і ввів його в мову.

Чому тестування не відбулося тієї ж еволюції мов програмування?


24
Чи справді краще зробити специфікацію мови більш складною, додавши синтаксис, на відміну від розробки мови з простими правилами, які легко можна розширити загальним способом?
KChaloux

6
Що ви маєте на увазі під «синтаксичним рівнем»? Чи є у вас деталі / ідеї щодо того, як це було б реалізовано?
SJuan76

21
Чи можете ви навести приклад тестування псевдокоду як функції, що підтримується синтаксисом? Мені цікаво побачити, як ви думаєте, як це виглядатиме.
FrustratedWithFormsDesigner

12
@FrustratedWithFormsDesigner Див мови D для прикладу.
Doval

4
Ще одна мова із вбудованими функціями тестування модулів - Rust.
Себастьян Редл

Відповіді:


36

Як і в багатьох випадках, тестування одиниць найкраще підтримується на рівні бібліотеки, а не на рівні мови. Зокрема, у C # є чимало бібліотек Unit Testing, а також речі, які є вродливими для .NET Framework Microsoft.VisualStudio.TestTools.UnitTesting.

Кожна бібліотека модульних тестувань має дещо іншу філософію та синтаксис тестування. За умови рівності, більше варіантів вибору краще, ніж менше. Якби тестові одиниці були викладені на мові, ви або будете заблоковані у виборі дизайнера мови, або ви будете використовувати ... бібліотеку, і взагалі уникати функцій тестування мови.

Приклади

  • Nunit - Загальна мета, ідіоматично розроблена одиниця тестування рамки, яка повністю використовує мовні особливості C #.

  • Moq - глузуючий фреймворк, який повністю використовує лямбда-вирази та дерева виразів, без метафори запису / відтворення.

Є багато інших варіантів. Бібліотеки, такі як Microsoft Fakes, можуть створювати макети "shim ...", які не вимагають писати свої класи за допомогою інтерфейсів або віртуальних методів.

Linq - це не мовна функція (незважаючи на назву)

Linq - функція бібліотеки. Ми отримали багато нових функцій у самій мові C # безкоштовно, як лямбда-вирази та методи розширення, але реальна реалізація Linq знаходиться у .NET Framework.

Існує деякий синтаксичний цукор, який було додано до C #, щоб зробити чистіші твердження linq, але цей цукор не потрібно використовувати linq.


1
Я погоджуюсь з тим, що LINQ не є мовною особливістю, але для того, щоб LINQ стався, потрібно було мати деякі основні мовні функції, зокрема, загальні та динамічні типи.
Wyatt Barnett

@WyattBarnett: Так, і те саме стосується легкого тестування одиниць - як відображення та атрибути.
Doc Brown

8
LINQ потребували лямбда і виразних дерев. Generics вже були в C # (і .Net взагалі вони присутні в CLR), і динаміка не має нічого спільного з LINQ; ви можете робити LINQ без динаміки.
Артур ван Левенен

DBIx :: Class Perl є прикладом функціональності, подібного до LINQ, впровадженого понад 10 років після того, як усі функції, необхідні для його реалізації, були на мові.
slebetman

2
@ Carson63000 Я думаю, ви маєте на увазі анонімні типи в поєднанні з varключовим словом :)
М.Мімпен

21

Причин багато. Ерік Ліпперт багато разів заявляв, що причина feature Xне в C #, тому що це просто не в їхньому бюджеті. Мовні дизайнери не мають нескінченної кількості часу та грошей на реалізацію речей, і кожна нова функція пов’язана з цим витрат на обслуговування. Збереження мови якомога меншою не просто для мовних дизайнерів - це також простіше для всіх, хто пише альтернативні реалізації та інструменти (наприклад, IDE). Крім того, коли щось реалізується з точки зору мови, а не з її частини, ви отримуєте портативність безкоштовно. Якщо тестування одиниць реалізовано як бібліотека, вам потрібно написати лише один раз, і вона працюватиме в будь-якій відповідній реалізації мови.

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

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

Однак я думаю, що велика бібліотека тестування блоків робить набагато більше, ніж просто знайти деякі методи та запустити їх. Візьмемо для прикладу QuickCheck Haskell , який дозволяє перевірити такі речі, як "для всіх x і y f (x, y) == f (y, x)". QuickCheck краще описується як одиничний тестовий генератор і дозволяє перевірити речі на більш високому рівні, ніж "для цього вводу, я очікую цього результату". QuickCheck та Linq не так вже й різняться - вони обидві доменні мови. Тож, замість того, щоб зафіксувати підтримку модульного тестування на мові, чому б не додати функції, необхідні для того, щоб зробити DSL практичними? Ви закінчите не просто тестування, але й кращу мову.


3
Щоб залишитися у світі .Net, є FsCheck, який є портом QuickCheck до F #, з деякими помічниками для використання від C #.
Артур ван Левен

Щоб залишитися у світі .NET? Це питання не має нічого спільного з .NET.
Майлз Рут

@MilesRout C # входить до .NET. Питання та відповіді часто говорять про C #, а питання навіть про LINQ.
Zachary Dow

Питання не позначено тегами .NET або C #.
Майлз Рут

@MilesRout Це може бути правдою, але ви не можете обґрунтовано сказати, що це не має нічого спільного лише тому, що він не має тегу. :)
Zachary Dow

13

Тому що тестування, і особливо тестова розробка, є глибоко контрінтуїтивним явищем.

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

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

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


3
Ви трохи завищуєте свою справу. Хоча тестування одиниць є безперечно важливим, однаково важливим є побудова програм належним чином, спосіб мінімізації зайвої складності, якщо не більше. Такі мови, як Haskell, мають типові системи, які покращують надійність та надійність програм, написаних на них, а найкращі практики кодування та дизайну уникають багатьох підводних каменів неперевіреного коду, що робить тестування одиниць менш критичним, ніж це було б інакше.
Роберт Харві

1
@RobertHarve ... і тестування блоків - це дуже хороший спосіб опосередковано підштовхнути розробників до цього. Робота над API при створенні тестів, а не при використанні його з іншим кодом, допомагає встановити їх у правильному режимі мислення, щоб обмежити або видалити витікаючі абстракції або незвичні виклики методів. Я не думаю, що KillianFoth нічого не завищує.
Ізката

@ Роберт: Єдине, що я вважаю, що він завищує, це "релігійне тестування повільно стає більш основним". Якщо повільно визначається в географічних часових межах, він, ймовірно, не за горами ..... :)
mattnz

+1 На моїй нинішній роботі мене вражає припливний зміна настрою розвитку з використанням нових бібліотек та технологій, які доступні. Вперше в моїй кар'єрі ці хлопці навчають мене використовувати більш складний процес розвитку, замість того, щоб я відчував, що я на вершині пагорба, що кричить на вітер. Я погоджуюся, що це лише час, коли ці позиції знайдуть своє вираження в синтаксисі рідної мови.
Роб

1
Вибачте, ще одна думка про коментар Роберта Харві. Зараз типи систем - це хороша перевірка, але насправді не вистачає визначення обмежень для типів - вони адресують інтерфейс, але не обмежують правильну поведінку. (тобто 1 + 1 == 3 буде компілюватися, але може бути, а може і не бути істинним, залежно від реалізації +) Цікаво, чи буде наступна тенденція бачити більш виразні системи типів, які поєднують те, що ми вважаємо одиничним тестуванням зараз.
Роб

6

Багато мов мають підтримку тестування. Ствердження C - це тести, які програма може вийти з ладу. Ось де зупиняється більшість мов, але у Ейфеля та останніх часів Ada 2012 є предіваріанти (речі, які повинні переходити аргументи функції) та постінваріанти (речі, які мають виходити з функції), і Ada пропонує можливість посилатися на початкові аргументи в постінваріантний. Ada 2012 також пропонує інваріанти типів, тому щоразу, коли метод викликається на клас Ada, інваріант типу перевіряється перед поверненням.

Це не той тип повного тестування, який може дати вам хороша рамка тестування, але це важливий тип тестування, який мови можуть найкраще підтримувати.


2
Трохи попрацювавши в Ейфелі і будучи широким користувачем тверджень, мій досвід засвідчив, що все, що ти можеш зробити, що має контрактний характер, допомагає вивести багато помилок.
Blrfl

2

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

Два, imho, хороший приклад цього для цього - від F # for Fun and Profit тут і тут

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


2

Я можу стверджувати, що ви пропустили додавання деяких необхідних функцій, оскільки вони не були виділені як для тестування одиниць .

Наприклад, тестування одиниць на C # в основному здійснюється за допомогою атрибутів. Функція користувальницьких атрибутів забезпечує багатий механізм розширення, який дозволяє рамкам, як NUnit, повторювати та конкурувати з такими речами, як Теоретичне та Параметризоване тестування.

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

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

Інше відповідне читання:

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