In F #, voglio costruire una struttura gerarchica dei dati in un modo con un minimo quantità di rumore del linguaggio. Il vero problema è provare a creare un RSpec framework ispirato usando F #. RSpec consente la costruzione di test in modo annidato. Ad esempio.
describe Order do
context "with no items" do
it "behaves one way" do
# ...
end
end
context "with one item" do
it "behaves another way" do
# ...
end
end
end
Ho qualcosa che funziona qui , ma ci sono alcuni potenziali problemi con la soluzione attuale. In particolare generale il codice di setup / teardown può diventare alquanto brutto.
La mia preoccupazione principale è scrivere un'API che permetta all'utente di scrivere test / specifiche in un modo, in cui la lingua diventa così piccola come possibile.
Penso che l'uso delle espressioni di calcolo possa consentire al mio di creare una migliore API, ma sono in difficoltà con l'implementazione di contesti nidificati.
Attualmente ho un builder che mi permette di scrivere:
let specs =
describe "Some feature" {
it "has some behavior" (fun () ->
// Test code goes here
)
}
Ma per avere contesti annidati devo essere in grado di scrivere qualcosa di simile in questo modo:
let specs =
describe "Some feature" {
describe "in some context" {
it "has some behavior" (fun () ->
// Test code goes here
)
}
describe "in some other context" {
it "has some behavior" (fun () ->
// Test code goes here
)
}
}
Non ho idea di come implementare il contesto nidificato. O anche se è possibile piega F # in modo da permettermi di creare un tale costruttore.
Ho fatto un esperimento, che mi ha permesso di scrivere questo:
let specs =
desribe "Some feature" {
child (describe "in some other" {
it "has some behavior" (fun () ->
// Test code goes here
)
})
child (describe "in some context" {
it "has some behavior" (fun () ->
// Test code goes here
)
})
}
Ma la parentesi aggiunta e la costruzione esplicita del builder sono esattamente ciò che io voglio evitare in primo luogo.
type DescribeBuilder(name : string) =
[<CustomOperation("it")>]
member __.It (x, name, test : unit -> unit) =
let t = TestContext.createTest name test
x |> TestContext.addTest t
[<CustomOperation("child")>]
member __.Child(x, child :TestContext.T) =
x |> TestContext.addChildContext child
member __.Yield y =
TestContext.create name
member __.Delay (x) =
x()
let describe name = new DescribeBuilder(name)