Sviluppo F # e unit test?


107

Ho appena iniziato con F #, che è il mio primo linguaggio funzionale. Ho lavorato quasi esclusivamente con C # e mi piace molto il modo in cui F # mi porta a ripensare a come scrivo il codice. Un aspetto che trovo un po 'disorientante è il cambiamento nel processo di scrittura del codice. Uso TDD da anni in C # e apprezzo molto i test unitari per sapere dove mi trovo.

Finora, il mio processo con F # è stato quello di scrivere alcune funzioni, giocarci con la console interattiva fino a quando non sono "ragionevolmente" sicuro che funzionino, e modificare e combinare. Funziona bene su problemi su piccola scala come il Progetto Eulero, ma non riesco a immaginare di costruire qualcosa di grande in questo modo.

In che modo le persone affrontano i test di unità e creano una suite di test per un programma F #? Esiste un equivalente a TDD? Eventuali suggerimenti o pensieri sono apprezzati.


1
expert-fsharp.com/CodeSamples/Forms/… mostra un semplice esempio di utilizzo di NUnit con F #.
itowlson


correlato: stackoverflow.com/questions/5667372/… (Unquote è molto più di una nota a piè di pagina / commento poiché è all'interno del set di risposte in questa pagina)
Ruben Bartelink

Una cosa che manca in queste risposte è un esempio appropriato di Foq, AutoFixture.AutoFoq e AutoFixture.xUnit alleati con l'inferenza del tipo di F #. Vedi trelford.com/blog/post/test5.aspx e trelford.com/blog/post/fstestlang.aspx per un assaggio e un giorno scriverò una risposta corretta qui
Ruben Bartelink

Risposte:


77

Gli sviluppatori basati sui test dovrebbero sentirsi a casa in linguaggi funzionali come F #: piccole funzioni che forniscono risultati ripetibili in modo deterministico si prestano perfettamente agli unit test. Esistono anche funzionalità nel linguaggio F # che facilitano la scrittura di test. Prendi, ad esempio, Object Expressions . Puoi scrivere facilmente falsi per funzioni che prendono come input un tipo di interfaccia.

Se non altro, F # è un linguaggio orientato agli oggetti di prima classe e puoi usare gli stessi strumenti e trucchi che usi quando esegui TDD in C #. Sono disponibili anche alcuni strumenti di test scritti o specificatamente per F #:

Matthew Podwysocki ha scritto una serie fantastica sui test di unità nei linguaggi funzionali. Anche lo zio Bob ha scritto un articolo stimolante qui .


9
Ho anche sviluppato (e sto sviluppando attivamente) una libreria di unit test specifica per F # chiamata Unquote: code.google.com/p/unquote . Consente di scrivere asserzioni di test come espressioni booleane F # semplici e controllate staticamente utilizzando citazioni F # e produce automaticamente messaggi di errore di test piacevoli. Funziona senza configurazione con supporto speciale sia per xUnit.net che per NUnit e generalmente supporta qualsiasi framework di unit test basato su eccezioni. Funziona anche all'interno delle sessioni FSI consentendo la migrazione senza soluzione di continuità dai test interattivi alle suite di test formali.
Stephen Swensen

C'è anche Pex , anche se è un po 'più difficile da brontolare.
Benjol

1
Uncle bob link sembra morto
Aage

22

Uso NUnit e non mi sembra difficile da leggere o oneroso da scrivere:

open NUnit.Framework

[<TestFixture>]
type myFixture() = class

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

end

Poiché il mio codice è un mix di F # e altri linguaggi .Net, mi piace il fatto che scrivo gli unit test sostanzialmente nello stesso modo e con sintassi simile sia in F # che in C #.


4
Dopo aver letto altre risposte qui, ho provato FSUnit e penso che sia fantastico. Funziona bene con TestDriven.Net (come fa NUnit), incoraggia uno stile fluido di scrittura di test auto-documentanti e, come afferma Ray, è "più a suo agio nei linguaggi F #". Non male per 21 righe di codice! (E un paio di consigli su layout / denominazione). Due brevi note: 1. La DLL FSUnit precompilata non ha funzionato per me. La compilazione dall'origine (FsUnit.NUnit-0.9.0.fs) ha risolto il problema. 2. TestDriven.Net non riconosce i nomi TextFixture che sembrano `like this`. I nomi dei test che utilizzano il modulo a doppia spunta vengono riconosciuti.
David Glaubman,

15

Dai un'occhiata a FsCheck , uno strumento di test automatico per F #, che è fondamentalmente un port di QuickCheck di Haskell. Consente di fornire una specifica del programma, sotto forma di proprietà che le funzioni oi metodi dovrebbero soddisfare, e FsCheck verifica che le proprietà contengano in un gran numero di casi generati casualmente.

FsCheck CodePlex Page

Pagina dell'autore di FsCheck


Sì, penso che FsCheck offra molto di più dei tradizionali framework di unit test come NUnit ecc.
Robert

11

Come suggerisce dglaubman, puoi usare NUnit. xUnit.net fornisce anche il supporto per questo e funziona bene con TestDriven.net . Il codice è simile ai test NUnit ma senza la necessità di racchiudere il test in un tipo contenitore.

#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) 

A partire dalla 1.9.1 i nuovi sovraccarichi di Xunit sembrano causare il caos con il mio F #.
Rick Minerich

@RickMinerich Ho sperimentato la stessa cosa accadendo al mio codice. Ho appena finito per aggiungere annotazioni di tipo esplicito in modo da scegliere il sovraccarico corretto. Tuttavia, questo non aggiunge più rumore al codice purtroppo.
Erik Schierboom

11

Penso che questa sia una domanda molto interessante su cui mi sono chiesto molto io stesso. I miei pensieri finora sono solo pensieri, quindi prendili per quello che sono.

Penso che la rete di sicurezza di una suite di test automatizzata sia una risorsa troppo preziosa per lasciarla andare, per quanto allettante possa essere quella console interattiva, quindi ho intenzione di continuare a scrivere test unitari come ho sempre fatto.

Uno dei principali punti di forza di .NET sono le capacità cross-language. So che presto scriverò il codice di produzione F #, ma il mio piano è scrivere unit test in C # per facilitare il mio passaggio a quello che per me è un nuovo linguaggio. In questo modo, posso anche verificare che ciò che scrivo in F # sarà compatibile con C # (e altri linguaggi .NET).

Con questo approccio, capisco che ci sono alcune funzionalità di F # che posso usare solo internamente nel mio codice F #, ma non esporre come parte della mia API pubblica, ma lo accetterò, così come accetto oggi che ci sono certe cose C # mi consente di esprimere (mi piace uint) che non sono conformi a CLS, quindi mi astengo dall'usarli.


2
Come stava andando il tuo piano? È stato facile testare il codice f # con il codice c #? Ho iniziato a imparare f # e il mio piano è scrivere una parte del mio progetto in f # e ho la stessa idea: scrivere unit test in c # anche per f #.
Peter Porfy

@ Segnare eventuali aggiornamenti? Inoltre sto avendo difficoltà a entrare nel flusso usando TDD con F #.
Scott Nimrod

1
@ScottNimrod Alcuni aggiornamenti: quattro dei miei corsi Pluralsight riguardano i test o il TDD con F #. Troverai anche molte registrazioni gratuite di conferenze sul mio profilo Lanyrd . Infine, c'è il mio blog .
Mark Seemann

3
@ScottNimrod Non posso raccomandare di prendersi il tempo e / o pagare i soldi per visualizzare abbastanza bene il set completo dei corsi PS di Mark: ti farà scattare tutto insieme nella tua testa con la massima efficienza. Sebbene possa o meno essere applicabile alle tue esigenze specifiche, "A Functional Architecture in F #" collega anche molti punti e dovrebbe anche essere presa in considerazione.
Ruben Bartelink

7

Potresti dare un'occhiata a FSUnit , anche se non l'ho ancora usato, potrebbe valere la pena provare. Sicuramente migliore rispetto all'utilizzo ad esempio (nativo) di NUnit in F #.


1
ShdNx, perché consiglieresti contro NUnit? Il libro F # di Don Syme mostra NUnit per i test e sembra abbastanza simile all'uso di NUnit in C #. FSUnit DSL sembra interessante, ma per le persone che hanno già familiarità con NUnit (Mathias "usa TDD da anni") è la tua esperienza che l'utilizzo di NUnit con F # è più problematico che con C # o VB?
itowlson

Secondo itowlson commento e domanda. Sicuramente NUnit in F # sembra piuttosto strano, ma a parte questo, sei a conoscenza di problemi specifici che rendono una buona idea usare qualcos'altro?
Mathias

1
Direi che "avere un aspetto piuttosto strano" è di solito un motivo convincente per trovare qualcosa di meglio. Sembra strano significa difficile da leggere e difficile da leggere significa bug. (Presumo che "sembrare strano" sia completamente diverso da "sembrare nuovo e / o sconosciuto" - sconosciuto diventerà familiare, strano rimarrà strano.)
James Moore

1
Ad essere onesti (come ho menzionato nella mia risposta), non ho ancora usato FSUnit, ma ho letto che è molto doloroso usare NUnit in F #. Scusa se non è così.
ShdNx

4
Per essere chiari, avrai ancora TestFixtures e membri di Test se usi FsUnit. Quello che non avrai sono le chiamate Assert.X standard. FsUnit offre semplicemente un wrapper attorno a questa parte di NUnit che lo rende più a suo agio nel linguaggio F #.
Ray Vernagus

1

Nonostante sia un po 'in ritardo alla festa, vorrei dare il benvenuto a Mathias in F # (meglio tardi che mai;)) e farmi notare che potrebbe piacerti la mia libreria di unit test, Expecto

Expecto ha alcune funzionalità che potrebbero piacerti:

  • Sintassi F # in tutto, test come valori; scrivi in ​​F # semplice per generare test
  • Usa il modulo Expect integrato o una libreria esterna come Unquote per le asserzioni
  • Test paralleli per impostazione predefinita
  • Prova il tuo codice Hopac o il tuo codice Async; Expecto è asincrono dappertutto
  • Registrazione e metriche collegabili tramite Logary Facade; scrivere facilmente adattatori per sistemi di compilazione o utilizzare il meccanismo di temporizzazione per creare un dashboard InfluxDB + Grafana dei tempi di esecuzione dei test
  • Supporto integrato per BenchmarkDotNet
  • Build in supporto per FsCheck; semplifica la creazione di test con dati generati / casuali o la creazione di modelli invarianti dello spazio degli stati dell'oggetto / attore

-

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/

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.