F # розробка та тестування одиниць?


107

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

Поки мій процес з F # полягав у написанні деяких функцій, відтворенні з ними за допомогою інтерактивної консолі, поки я не буду "впевнено" впевнений, що вони працюють, і налаштувати та комбінувати. Це добре працює в масштабних проблемах, таких як проект Ейлера, але я не можу уявити, щоб створити щось таке велике.

Як люди підходять до тестування одиниць і створення тестового набору для програми F #? Чи є еквівалент TDD? Будь-які вказівки чи думки цінуються.


1
expert-fsharp.com/CodeSamples/Forms/… показує простий приклад використання NUnit з F #.
itowlson


пов'язані: stackoverflow.com/questions/5667372/… (Котирування - це набагато більше, ніж виноска / коментар, як це є у відповіді на цій сторінці)
Рубен Бартелінк,

У цих відповідях відсутнє одне - належний приклад Foq, AutoFixture.AutoFoq та AutoFixture.xUnit, що поєднується з висновком типу F #. Дивіться trelford.com/blog/post/test5.aspx та trelford.com/blog/post/fstestlang.aspx для дегустатора, і якихось день напишу тут належну відповідь
Ruben Bartelink

Відповіді:


77

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

Якщо що-небудь, F # - це першокласна об'єктно-орієнтована мова, і ви можете використовувати ті самі інструменти та хитрощі, які ви використовуєте під час виконання TDD в C #. Існують також деякі інструменти тестування, написані або спеціально для F #:

Метью Подвісоцький написав чудову серію про тестування одиниць на функціональних мовах. Дядько Боб також написав тут статтю, що провокує думку .


9
Я також розробив (і активно розвиваю) бібліотеку для тестування специфічних одиниць F # під назвою Unquote: code.google.com/p/unquote . Це дозволяє записувати тестові твердження як прості, статично перевірені F # булеві вирази за допомогою котирувань F # і автоматично створює приємні повідомлення про помилку тесту. Він працює без конфігурації зі спеціальною підтримкою як для xUnit.net, так і для NUnit і, як правило, підтримує будь-які рамки тестування на основі винятків. Він навіть працює в рамках сесій FSI, що дозволяє легко перейти від інтерактивного тестування до формальних тестових наборів.
Стівен Швенсен

Там в Pex теж, хоча це трохи складніше звертав уваги.
Benjol

1
Дядя Боб посилання здається мертвим
Aage

22

Я використовую NUnit, і мені це не здається важким для читання або обтяжливим для написання:

open NUnit.Framework

[<TestFixture>]
type myFixture() = class

    [<Test>]
    member self.myTest() =
       //test code

end

Оскільки мій код є сумішшю F # та інших мов .Net, мені подобається те, що я пишу одиничні тести в основному однаково і з подібним синтаксисом як у F #, так і в C #.


4
Прочитавши інші відповіді тут, я спробував FSUnit, і я думаю, що це чудово. Він добре працює з TestDriven.Net (як і NUnit), заохочує рідкий стиль написання тестів самодокументування та, як зазначає Рей, "більше вдома на мовах F #". Непогано для 21 рядка коду! (І пару рекомендацій щодо компонування / іменування). Дві швидкі примітки: 1. Попередньо складений DLL для FSUnit не працював для мене. Побудова з джерела (FsUnit.NUnit-0.9.0.fs) вирішила проблему. 2. TestDriven.Net не розпізнає імена TextFixture, які виглядають `like this`. Імена тестів за допомогою форми подвійного галочки розпізнаються
Девід Глаубман

15

Погляньте на FsCheck , автоматичний інструмент тестування для F #, в основному це порт QuickCheck Haskell. Це дозволяє надати специфікацію програми у вигляді властивостей, яким повинні задовольняти функції чи методи, та тестів FsCheck, які властивості містять у великій кількості випадково генерованих випадків.

Сторінка FsCheck CodePlex

Сторінка автора FsCheck


Так, я думаю, що FsCheck пропонує набагато більше, ніж традиційні рамки тестування одиниць, такі як NUnit тощо.
Роберт

11

Як пропонує dglaubman, ви можете використовувати NUnit. xUnit.net також надає підтримку для цього і добре працює з TestDriven.net . Код схожий на тести NUnit, але без вимоги переносити тест у тип, що містить.

#light

// Supply a module name here not a combination of module and namespace, otherwise
// F# cannot resolve individual tests nfrom the UI.
module NBody.DomainModel.FSharp.Tests

open System
open Xunit

open Internal

[<Fact>]
let CreateOctantBoundaryReordersMinMax() =
    let Max = VectorFloat(1.0, 1.0, 1.0)
    let Min = VectorFloat(-1.0, -1.0, -1.0)

    let result = OctantBoundary.create Min Max

    Assert.Equal(Min, result.Min)     
    Assert.Equal(Max, result.Max) 

З 1.9.1 нові перевантаження Xunit, здається, спричиняють хаос із моїм F #.
Рік Мінерих

@RickMinerich У мене виникло те саме, що відбувається з моїм кодом. Я щойно додав явні анотації типу, щоб було обрано правильне перевантаження. Однак це , на жаль, додає більше шуму вашому коду.
Ерік Щербум

11

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

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

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

При такому підході я розумію, що є певні особливості F #, які я можу використовувати лише внутрішньо у своєму коді F #, але не виставляти її як частину свого публічного API, але я прийму це, як і сьогодні приймаю, що є певні речі C # дозволяє мені висловити (як uint), які не відповідають сумісності CLS, і тому я утримуюсь від їх використання.


2
Як відбувався ваш план? Легко було перевірити f # код за допомогою c # коду? Я почав вивчати f #, і мій план полягає в тому, щоб написати частину мого проекту у f #, і я маю ту саму ідею: писати одиничні тести в c # для f # теж.
Пітер Порфі

@Маркувати якісь оновлення? У мене також важко потрапляти в потік, використовуючи TDD з F #.
Скотт Німрод

1
@ScottNimrod Досить декілька оновлень: чотири мої курси Pluralsight стосуються тестування або TDD з F #. Ви також знайдете безліч безкоштовних записів конференційних переговорів на моєму профілі Lanyrd . Нарешті, є мій блог .
Марк Семанн

3
@ScottNimrod Я не можу порекомендувати витратити час та / або заплатити гроші, щоб переглянути повний набір курсів ПС Марка досить високо - це все це зграє в голові з максимальною ефективністю. Хоча це може або не стосується ваших конкретних потреб, "Функціональна архітектура у F #" також з'єднує безліч крапок, і їх також слід уважно розглянути.
Рубен Бартелінк

7

Ви можете поглянути на FSUnit - хоча я ще цього не використовував, варто спробувати. Звичайно, краще, ніж використовувати наприклад (рідний) NUnit у F #.


1
ShdNx, чому б ви рекомендували проти NUnit? У книзі F # Don Syme показано NUnit для тестування, і він виглядає досить схоже на використання NUnit в C #. FSUnit DSL виглядає круто, але для людей, які вже знайомі з NUnit (Mathias "використовує TDD роками"), чи є ваш досвід, що використовувати NUnit з F # більш проблематично, ніж із C # або VB?
itowlson

Я другий коментар itowlson і питання. Напевно, NUnit у F # виглядає досить дивним, але крім цього, чи знаєте ви конкретні проблеми, які дозволяють використовувати щось інше?
Матіас

1
Я б сказав, що «дивлячись досить дивно», як правило, є переконливою причиною знайти щось краще. Дивитись дивним - важко читати, а важко читати - означає помилки. (Я припускаю, що "дивно виглядати" зовсім інше, ніж "шукати нове та / або незнайоме" - незнайоме стане звичним, незвичайне залишиться дивним.)
Джеймс Мур

1
Якщо чесно (як я вже згадував у своїй відповіді), я ще не використовував FSUnit, але я читав, що використовувати NUnit у F # дуже боляче. Вибачте, якщо це не так.
ShdNx

4
Щоб було зрозуміло, у вас все ще будуть TestFixtures та тестові члени, якщо ви використовуєте FsUnit. У вас не буде стандартних викликів Assert.X. FsUnit просто дає обгортку навколо цієї частини NUnit, що робить її більш домашньою мовою F #.
Рей Вернагус

1

Незважаючи на те, що трохи запізнився на вечірку, я хотів би привітати Матіаса до F # (краще пізніше, ніж ніколи)) і задзвонити, що, можливо, вам сподобається моя тестова бібліотека, Expecto

Expecto має деякі функції, які вам можуть сподобатися:

  • F # синтаксис протягом, тестує як значення; написати звичайний F # для генерації тестів
  • Використовуйте вбудований модуль Expect або зовнішню вкладку, як Unquote для тверджень
  • Паралельні тести за замовчуванням
  • Перевірте свій код Hopac або код Async; Expecto асинхронізується протягом усього часу
  • Підключення до журналу та метрики через Logary Facade; легко записуйте адаптери для систем побудови або використовуйте механізм синхронізації для побудови інформаційної панелі InfluxDB + Grafana строків виконання ваших тестів
  • Вбудована підтримка BenchmarkDotNet
  • Створіть підтримку FsCheck; дозволяє легко будувати тести з генерованими / випадковими даними або будувати інваріантні моделі простору стану вашого об'єкта / актора

-

open Expecto

let tests =
  test "A simple test" {
    let subject = "Hello World"
    Expect.equal subject "Hello World" "The strings should equal"
  }

[<EntryPoint>]
let main args =
  runTestsWithArgs defaultConfig args tests

https://github.com/haf/expecto/

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