I'm writing unit tests in F# using FsUnit and NUnit, with the NUnit test adapter for VS2015 Ultimate CTP. I've come across an odd issue with a module member being null, where I wouldn't expect it to be.
Is this an issue with the the code, or the way the tests are executed?
I've tried changing the signature of Foo.SpecificFooStrategy.create to unit -> FooStrategy (let create = fun () -> ...) and invoking as Foo.SpecificFooStrategy.create (), but that hasn't helped.
Code
namespace Foo
// FooStrategy.fs
module FooStrategy =
type FooStrategy =
| FooStrategy of A * B
with
member x.A =
match x with
| FooStrategy(a, _) -> a
member x.B =
match x with
| FooStrategy(_, b) -> b
let create a b = FooStrategy(a, b)
// SpecificFooStrategy.fs
module SpecificFooStrategy =
let private a = // ...
let private b = // ...
let create =
FooStrategy.create a b
Test
namespace Foo.Tests
[<TestFixture>]
module SpecificFooStrategyTests =
[<Test>]
let ``foo is something`` ()=
let strategy = Foo.SpecificFooStrategy.create
strategy // strategy is null here
|> An.operationWith strategy
|> should equal somethingOrOther
In the code, create is not a function but a value.
It can be fixed by defining it as a function:
let create() = …
and calling it with parens:
let strategy = Foo.SpecificFooStrategy.create()
Related
I have issues with generation of data within my tests.
testProperty "calculate Operation against different operations should increase major" <| fun operationIdApi operationIdClient summaryApi summaryClient descriptionApi descriptionClient ->
( notAllEqual [
fun () -> assessEquality <| StringEquals(operationIdApi, operationIdClient)
fun () -> assessEquality <| StringEquals(summaryApi , summaryClient)
fun () -> assessEquality <| StringEquals(descriptionApi, descriptionClient)
]) ==> lazy (
let operationClient = createOpenApiOperation operationIdClient summaryClient descriptionClient
let operationAPI = createOpenApiOperation operationIdApi summaryApi descriptionApi
let actual = calculate operationAPI operationClient
Expect.equal actual (Fact.Semver.IncreaseMajor) "return IncreaseMajor"
)
The code that is actually tested is :
semver {
if operationAPI.OperationId<> operationClient.OperationId then yield! IncreaseMajor
if operationAPI.Summary <> operationClient.Summary then yield! IncreaseMajor
}
The test should fail when the data produced is same OperationId, same summary and different description.
But it does not and it led me to create my own generator or at least try to do so:
I wanted my test to be written like this :
testProperty "calculate Operation against different operations should increase major" <| fun (operationId:ElementSet<string>) (summary:ElementSet<string>) ->
Therefore I create a type accordingly:
type ElementSet<'a> =
| Same of 'a
| Different
and a generator for this type :
let setGen<'a> =
Gen.oneof [
gen {
let! v = Arb.generate<'a>
return Same(v)
}
gen { return Different}
]
type ElementSetGenerator =
static member ElementSet() =
Arb.fromGen setGen<'a>
do Arb.register<ElementSetGenerator>() |> ignore
I was then trying to extract the data to construct my object :
let createOpenApiOperation operationId summary=
let pi = OpenApiOperation(OperationId=operationId.Get, Summary=summary.Get)
pi
The Get method did not exist yet so I was about to implement it by adding a member to my ElementSet<'a>:
type ElementSet<'a> =
| Same of 'a
| Different
with member this.Get =
match this with
| Same s -> s
| Different -> Arb.generate<'a>// some random generation here
And this is where I am stuck. I would love to get some randomness here when I extract data. I wonder if this is the correct way to do so, or if I should have answered the problem earlier?
Thanks for your inputs.
I think I found it, the answer was to handle it at the beginning :
let setGen<'a when 'a:equality> =
Gen.oneof [
gen {
let! v = Arb.generate<'a>
return Same(v)
}
gen {
let! x,y =
Arb.generate<'a>
|> Gen.two
|> Gen.filter (fun (a,b)-> a <> b)
return Different(x,y)
}
]
and then to use two getter to access the values :
type ElementSet<'a> when 'a:equality=
| Same of 'a
| Different of 'a*'a
with member this.Fst = match this with | Same s -> s | Different (a, b)-> a
member this.Snd = match this with | Same s -> s | Different (a, b)-> b
this way I can access values within my test:
testProperty "calculate Operation against different operations should increase major" <| fun (operationId:ElementSet<NonWhiteSpaceString>) (summary:ElementSet<NonWhiteSpaceString>) (description:ElementSet<NonWhiteSpaceString>) ->
let operationClient = createOpenApiOperation operationId.Fst summary.Fst description.Fst
let operationAPI = createOpenApiOperation operationId.Snd summary.Snd description.Snd
let actual = calculate operationAPI operationClient
Expect.equal actual (Fact.Semver.IncreaseMajor) "return IncreaseMajor"
for the record I then have the creation of my stub as follows :
let createOpenApiOperation (operationId:NonWhiteSpaceString) (summary:NonWhiteSpaceString) (description:NonWhiteSpaceString)=
let pi = OpenApiOperation(OperationId=operationId.Get, Summary=summary.Get, Description=description.Get)
pi
Have I correctly implemented map for Task?
let map continuation (t: Task<'A>) =
t.ContinueWith(fun (antecedent: Task<'A>) ->
if antecedent.Status <> TaskStatus.Canceled &&
antecedent.Status <> TaskStatus.Faulted then
continuation antecedent.Result
else
raise antecedent.Exception // must I?
)
I got the TaskStatus checks from the docs. I feel most uncertain about raise antecedent.Exception, but I can't think of another way to handle it.
As background, yes I'm aware of Async, but my current stack uses Entity Framework and Blazor, so I have a backend that uses things like .ToListAsync() and a front end in C#, so I'd rather just not deal with converting from Task to Async then back again.
I would suggest implementing your solution in terms of the interfaces behind the concept of awaitable in the TPL, namely INotifyCompletion and ICriticalNotifyCompletion. Also, to implement map correctly, you should really do it in terms of bind. This is something that there are already some existing solutions for in F#, such as the TaskBuilder library. Personally, I have been using the following in a library for years without any issues:
open System.Runtime.CompilerServices
open System.Threading.Tasks
type TaskStep<'result> =
| Value of 'result
| AsyncValue of 'result Task
| Continuation of ICriticalNotifyCompletion * (unit -> 'result TaskStep)
and StateMachine<'a>(firstStep) as this =
let methodBuilder = AsyncTaskMethodBuilder<'a Task>()
let mutable continuation = fun () -> firstStep
let nextAwaitable() =
try
match continuation() with
| Value r ->
methodBuilder.SetResult(Task.FromResult(r))
null
| AsyncValue t ->
methodBuilder.SetResult(t)
null
| Continuation (await, next) ->
continuation <- next
await
with
| exn ->
methodBuilder.SetException(exn)
null
let mutable self = this
member __.Run() =
methodBuilder.Start(&self)
methodBuilder.Task
interface IAsyncStateMachine with
member __.MoveNext() =
let mutable await = nextAwaitable()
if not (isNull await) then
methodBuilder.AwaitUnsafeOnCompleted(&await, &self)
member __.SetStateMachine(_) =
()
type Binder<'out> =
static member inline GenericAwait< ^abl, ^awt, ^inp
when ^abl : (member GetAwaiter : unit -> ^awt)
and ^awt :> ICriticalNotifyCompletion
and ^awt : (member get_IsCompleted : unit -> bool)
and ^awt : (member GetResult : unit -> ^inp) >
(abl : ^abl, continuation : ^inp -> 'out TaskStep) : 'out TaskStep =
let awt = (^abl : (member GetAwaiter : unit -> ^awt)(abl))
if (^awt : (member get_IsCompleted : unit -> bool)(awt))
then continuation (^awt : (member GetResult : unit -> ^inp)(awt))
else Continuation (awt, fun () -> continuation (^awt : (member GetResult : unit -> ^inp)(awt)))
module TaskStep =
let inline bind f step : TaskStep<'a> =
Binder<'a>.GenericAwait(step, f)
let inline toTask (step: TaskStep<'a>) =
try
match step with
| Value x -> Task.FromResult(x)
| AsyncValue t -> t
| Continuation _ as step -> StateMachine<'a>(step).Run().Unwrap()
with
| exn ->
let src = new TaskCompletionSource<_>()
src.SetException(exn)
src.Task
module Task =
let inline bind f task : Task<'a> =
TaskStep.bind f task |> TaskStep.toTask
let inline map f task : Task<'b> =
bind (f >> Value) task
FsToolkit.ErrorHandling implements it here. I'll paste the current version below as it's quite short. It uses the TaskBuilder library Aaron mentioned.
module Task =
let singleton value = value |> Task.FromResult
let bind (f : 'a -> Task<'b>) (x : Task<'a>) = task {
let! x = x
return! f x
}
let map f x = x |> bind (f >> singleton)
Additionally, FSharpPlus has an independent implementation of Task.map here.
Throwing the exception again in the continuation would make for an incorrect stack trace.
It's a mapping from 'A -> 'B, so it's probably best to lay it out explicitly.
let rec map (continuation: 'A -> 'B) (t: Task<'A>) =
let rec map_resolved (task: Task<'A>) =
match task.Status with
| TaskStatus.RanToCompletion -> Task.FromResult(continuation task.Result)
| TaskStatus.Faulted -> Task.FromException<'B>(task.Exception)
| TaskStatus.Canceled -> Task.FromCanceled<'B>(CancellationToken.None)
| _ -> task.ContinueWith(map_resolved).Unwrap()
map_resolved t
I'm trying to build a log4net style interface in an F# assembly. The key attribute is exposing a static method that returns an instance of an object. log4net makes use of C# delegates to accomplish the task, e.g. with LogManager.GetLogger("log123"). Delegates, from my understanding, are less favored than functions-as-first-class for inward-facing F# libraries.
The simplified code below accomplishes the objective, but I am uncomfortable with the use of an F# reference cell to hold a map of instantiated objects. I am interested in feedback on whether my discomfort is warranted.
namespace Test
[<Interface>]
type IMyIface =
abstract member Addi : int -> int
[<Sealed>]
type TheMainObject internal (x:int) =
let mutable sum = x
interface IMyIface with
member this.Addi(y:int) = sum <- sum + y; sum
module internal Wrapr =
let mymap = ref Map.empty
let mgr s =
let m = !mymap
if Map.containsKey s m then m.[s]
else
let x = new TheMainObject(0)
mymap := m.Add(s, x)
x
[<Sealed>]
type Mgr() =
static member Get(n:string) =
Wrapr.mgr n :> IMyIface
Program.fs calls the library above as follows:
open Test
let a = Mgr.Get("hello")
printfn "%d" (a.Addi(1))
let c = Mgr.Get("hello")
printfn "%d, %A" (c.Addi(3)) (a = c) //prints 4, true
Thanks in advance for comments.
It's OK to use a reference cell internally to hold a mutable value. You could also use a .Net Dictionary instead of a map. This is the approach I took while building a Mini IoC Container. If you expect the function accessing the reference cell to be called from multiple threads then you should probably use a lock or other thread synchronization.
There are a number of ways of exposing the Get method. The static member approach you have taken is useful if you expect to overload the method. In which case you may consider using static let for static locals over a separate module:
type [<Sealed>] Mgr() =
static let sync = obj()
static let lookup = Dictionary()
static let obtain name =
match lookup.TryGetValue(name) with
| true, x -> x
| false,_ ->
let x = TheMainObject(0)
lookup.Add(name,x)
x
static member Get(name:string) =
lock sync (fun () -> obtain name :> IMyIface)
If you do not expect to overload the Get function then you could just use a module:
module Mgr =
let private lookup = ref Map.empty
let private obtain name =
match (!lookup).TryFind name with
| Some(x) -> x
| None ->
let x = TheMainObject(0)
lookup := (!lookup).Add(name,x)
x
let Get name = obtain name :> IMyIface
I have the following code snippet using the reactive extensions:
let value : 't = ...
Observable.Create<'t>(fun observer ->
let subject = new BehaviorSubject<'t>(value)
let d0 = subject.Subscribe(observer)
let d1 = observable.Subscribe(subject)
new CompositeDisposable(d0, d1) :> IDisposable
)
This works. However if I drop the upcast to IDisposable then the code fails
to compile, citing ambiguous overloads. However CompositeDisposable is an
IDisposable. Why is the type inference engine failing to resolve this? Note I use this pattern almost all the time in C# returning CompositeDisposable from Observable.Create without having to upcast.
As #kvb said, functions don't support variance so upcast is required for interfaces and subclasses.
Here is a small example demonstrating the behavior with subclasses:
type A() =
member x.A = "A"
type B() =
inherit A()
member x.B = "B"
let f (g: _ -> A) = g()
let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // fails
If function f is written by you, adding type constraints could help:
// This works for interface as well
let f (g: _ -> #A) = g()
let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // works
Otherwise, you have to do a litle upcast as your example described.
EDIT: Since F# 6.0, auto-upcasting of interfaces and subclasses is now supported by default.
trying to follow example in the expert f# book, and having an issue with the workflows...the code is as follows:
type Attempt<'a> = option<'a>
let succeed x = Some (x)
let fail = None
let bind p rest =
match p with
| None -> fail
| Some r -> rest r
let delay f = f()
type AttemptBuilder() =
member b.Return (x) = succeed x
member b.Bind (p, rest) = bind p rest
member b.Delay (f) = delay f
member b.Let (p, rest):Attempt<'a> = rest p //'
member b.ReturnFrom x = x
// using it:
let attempt = new AttemptBuilder()
let test foo =
attempt {
if not foo then return! fail else return foo
}
let check () =
attempt {
let! n1 = test true
let! n2 = test false
let! n3 = test true
let foo = n1,n2,n3
return foo
}
let foo = check ()
problem is , when all values are true, i get as expected, a Some(true, true, true), but if one of the values passed in is false, foo is null (!). Anyone ftw?
thanks!
This is just because None is actually represented as null at runtime (see the remarks on the Option<'T> page on MSDN). Also, note that you can add
member x.Zero() = fail
to your builder, and then you can write test as
let test x = attempt { if x then return foo }
which is a little cleaner to my eyes.