In che modo i programmatori funzionali testano le funzioni che restituiscono un'unità?In che modo i programmatori funzionali testano le funzioni che restituiscono un'unità?
Nel mio caso, credo che ho bisogno di unit test un'interfaccia per questa funzione:
let logToFile (filePath:string) (formatf : 'data -> string) data =
use file = new System.IO.StreamWriter(filePath)
file.WriteLine(formatf data)
data
Qual è l'approccio consigliato quando sono unità di test di una funzione con I/O?
In OOP, credo che un Test Spy possa essere sfruttato.
Il pattern Spia di prova si traduce in programmazione funzionale?
Il mio cliente simile a questa:
[<Test>]
let ``log purchase``() =
[OneDollarBill] |> select Pepsi
|> logToFile "myFile.txt" (sprintf "%A")
|> should equal ??? // IDK
Il mio dominio è la seguente:
module Machine
type Deposit =
| Nickel
| Dime
| Quarter
| OneDollarBill
| FiveDollarBill
type Selection =
| Pepsi
| Coke
| Sprite
| MountainDew
type Attempt = {
Price:decimal
Need:decimal
}
type Transaction = {
Purchased:Selection
Price:decimal
Deposited:Deposit list
}
type RequestResult =
| Granted of Transaction
| Denied of Attempt
(* Functions *)
open System
let insert coin balance = coin::balance
let refund coins = coins
let priceOf = function
| Pepsi
| Coke
| Sprite
| MountainDew -> 1.00m
let valueOf = function
| Nickel -> 0.05m
| Dime -> 0.10m
| Quarter -> 0.25m
| OneDollarBill -> 1.00m
| FiveDollarBill -> 5.00m
let totalValue coins =
(0.00m, coins) ||> List.fold (fun acc coin -> acc + valueOf coin)
let logToFile (filePath:string) (formatf : 'data -> string) data =
let message = formatf data
use file = new System.IO.StreamWriter(filePath)
file.WriteLine(message)
data
let select item deposited =
if totalValue deposited >= priceOf item
then Granted { Purchased=item
Deposited=deposited
Price = priceOf item }
else Denied { Price=priceOf item;
Need=priceOf item - totalValue deposited }
Le funzioni di stile di programmazione funzionale non hanno effetti collaterali. Poiché l'unica ragione plausibile per chiamare una funzione di ritorno all'unità diversa da "ignora" è per gli effetti collaterali, non ha senso chiedere quale sia il modo funzionale per testare un tipo di funzione che non si adatta allo stile funzionale . –
@JoelMueller Se ci pensate, lo stesso vale per Haskell dove non ci sono effetti collaterali, gli effetti sono espliciti nel sistema dei tipi. Non esiste ancora un modo semplice per testarli e il consiglio è ancora di limitare l'IO a un piccolo sottoinsieme del codice. Forse uno degli aspetti più utili della monade IO è semplicemente che se tutte le tue funzioni finiscono in 'IO', mostra che probabilmente stai facendo qualcosa di sbagliato! – TheInnerLight