web-dev-qa-db-fra.com

Développement F # et tests unitaires?

Je viens juste de commencer avec F #, qui est mon premier langage fonctionnel. Je travaille quasi-exclusivement avec C # et j'apprécie énormément le fait que F # me pousse à repenser la manière dont j'écris le code. Un aspect qui me désoriente un peu est le changement de processus d’écriture de code. J'utilise TDD depuis des années en C # et j'apprécie beaucoup de pouvoir passer des tests unitaires pour savoir où je suis.

Jusqu'à présent, mon processus avec F # consistait à écrire certaines fonctions, à les utiliser avec la console interactive jusqu'à ce que je sois "raisonnablement" sûr qu'elles fonctionnent, et à Tweak & combine. Cela fonctionne bien sur des problèmes à petite échelle comme le projet Euler, mais je ne peux pas imaginer construire quelque chose de grand de cette façon.

Comment les gens abordent-ils les tests unitaires et la construction d'une suite de tests pour un programme F #? Existe-t-il un équivalent à TDD? Tous les pointeurs ou pensées sont appréciés.

101
Mathias

Les développeurs guidés par les tests devraient se sentir à l'aise dans des langages fonctionnels comme F #: de petites fonctions donnant des résultats répétables de manière déterministe se prêtent parfaitement aux tests unitaires. Le langage F # offre également des fonctionnalités facilitant la rédaction de tests. Prenons, par exemple, Object Expressions . Vous pouvez très facilement écrire des faux pour des fonctions qui prennent en entrée un type d'interface.

Au contraire, F # est un langage orienté objet de première classe et vous pouvez utiliser les mêmes outils et astuces que vous utilisez lorsque vous utilisez TDD en C #. Il existe également des outils de test écrits ou spécialement pour F #:

Matthew Podwysocki a écrit une excellente série sur les tests unitaires en langages fonctionnels. Oncle Bob a également écrit un article qui suscite la réflexion ici .

73
Ray Vernagus

J'utilise NUnit, et cela ne me semble pas aussi difficile à lire ni aussi pénible à écrire:

open NUnit.Framework

[<TestFixture>]
type myFixture() = class

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

end

Étant donné que mon code est un mélange de langages F # et autres langages .Net, j'apprécie le fait que j'écris les tests unitaires de la même manière et avec une syntaxe similaire en F # et en C #.

22
David Glaubman

Jetez un oeil sur FsCheck, un outil de test automatique de F #, est fondamentalement un portage du QuickCheck de Haskell. Il vous permet de spécifier le programme .__ sous la forme de propriétés que les fonctions ou les méthodes doivent satisfaire, et FsCheck vérifie que les propriétés sont conservées dans un grand nombre de cas générés aléatoirement.

Page FsCheck CodePlex

Page Auteur FsCheck

15
primodemus

Je pense que c’est une question très intéressante à laquelle je me suis souvent posé beaucoup de questions. Mes pensées jusqu'à présent ne sont que des pensées, alors prenez-les pour ce qu'elles sont.

Je pense que le filet de sécurité d'une suite de tests automatisés est un atout trop précieux pour être laissé pour compte, aussi séduisant que puisse être cette console interactive, je prévois donc de continuer à écrire des tests unitaires comme je l'ai toujours fait.

L’une des principales forces de .NET réside dans ses capacités multilingues. Je sais que j'écrirai bientôt le code de production F #, mais mon plan est d'écrire des tests unitaires en C # pour faciliter mon entrée dans ce qui est pour moi un nouveau langage. De cette manière, je peux également vérifier que ce que j'écris en F # sera compatible avec C # (et d'autres langages .NET).

Avec cette approche, je comprends qu'il existe certaines fonctionnalités de F # que je ne peux utiliser qu'en interne dans mon code F #, mais que je n'expose pas dans le cadre de mon API publique, mais je l'accepterai, tout comme je l'accepte aujourd'hui. C # me permet d’exprimer (comme uint) des fichiers qui ne sont pas conformes à la norme CLS, et j’abstiens donc de les utiliser.

11
Mark Seemann

Comme suggéré par dglaubman, vous pouvez utiliser NUnit. xUnit.net fournit également un support pour cela et fonctionne bien avec TestDriven.net . Le code ressemble à celui des tests NUnit mais ne nécessite pas de placer le test dans un type contenant.

#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) 
11
Ade Miller

Vous pouvez consulter FSUnit - bien que je ne l’aie pas encore utilisé, cela pourrait valoir la peine d’être essayé. Certainement mieux que d’utiliser par exemple NUnit (native) en F #.

7
ShdNx

Bien que je sois un peu en retard à la fête, j'aimerais souhaiter la bienvenue à Mathias en F # (mieux vaut tard que jamais;)) et au carillon dans lequel vous pourriez aimer Expecto

Expecto a quelques fonctionnalités qui pourraient vous plaire:

  • La syntaxe F # tout au long, teste en tant que valeur; écrire en clair F # pour générer des tests
  • Utilisez le module intégré Expect ou une bibliothèque externe telle que Unquote for assertions
  • Tests parallèles par défaut
  • Testez votre code Hopac ou votre code Async. Expecto est async
  • Journalisation et métrique enfichables via Logary Facade; écrivez facilement des adaptateurs pour les systèmes de construction, ou utilisez le mécanisme de minutage pour créer un tableau de bord InfluxDB + Grafana des temps d'exécution de vos tests
  • Prise en charge intégrée de BenchmarkDotNet
  • Construire un support pour FsCheck; facilite la construction de tests avec des données générées/aléatoires ou la construction de modèles invariants de l'espace d'état de votre objet/acteur

-

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/

1
Henrik