How to use NUnit with F# properly? - f#

I have stucked with the unit testing. I have the following source code:
module SampleTest
open FsUnit
open NUnit.Framework
[<TestFixture>]
[<Category("Category name")>]
type DoSthTest() =
let mutable state = []
[<SetUp>]
member public x.``run before test``() =
state = []
[<Test>]
member x.``add item``() =
state <- List.append state [1]
state.Length |> should equal 1
In general it runs fine.... but without the [] function.
I got the following exception: Result Message: Invalid signature for SetUp or TearDown method: run before test
Does someone know the answer why ?
And the second question is: is it possible to write an unittest without type definition but with the SetUp also function working?
I mean sth like this:
module SampleTest
open FsUnit
open NUnit.Framework
let mutable state = []
[<SetUp>]
let ``run before test``() =
state = []
[<Test>]
let ``add item``() =
state <- List.append state [1]
state.Length |> should equal 1
again I got the same exception as before

In F#, mutable values are assigned using <- rather than =.
So your Setup method should look like:
[<SetUp>]
member public x.``run before test``() =
state <- []
which works fine.
For your second question, this layout works fine for me if you make the same change as above.

Related

FSharp.Compiler.Service FSharpChecker fails to compile dynamic assembly when referencing IAsyncDisposable

Running the following in a dotnet core 3.1 console application fails to compile the assembly:
module Test
open FSharp.Compiler.SourceCodeServices
open FSharp.Compiler.Text
let source = """module Test
type TestType() =
interface System.IAsyncDisposable with
member __.DisposeAsync() =
System.Threading.Tasks.ValueTask()
"""
let references =
[
"Microsoft.Bcl.AsyncInterfaces"
]
[<EntryPoint>]
let main(args) =
let checker = FSharpChecker.Create()
let options =
{ FSharpParsingOptions.Default with
SourceFiles = [|"empty.fs"|]
}
let sourceText = SourceText.ofString source
let parseResult =
checker.ParseFile("empty.fs", sourceText, options) |> Async.RunSynchronously
let input = parseResult.ParseTree.Value
let thisAssembly =
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
let allReferences =
thisAssembly :: references
let errors, _, assemblyOpt =
checker.CompileToDynamicAssembly([input], "TestProject", allReferences, None)
|> Async.RunSynchronously
0
assemblyOpt is None and the errors array contains the following messages:
The type 'IAsyncDisposable' is not defined in 'System'. Maybe you want one of the following:
IDisposable
The type 'obj' is not an interface type
The type 'IAsyncDisposable' is not defined in 'System'. Maybe you want one of the following:
IDisposable
The type 'IAsyncDisposable' is not defined in 'System'. Maybe you want one of the following:
IDisposable
This type is not an interface type
No abstract or interface member was found that corresponds to this override
The value, constructor, namespace or type 'ValueTask' is not defined.
p_tyar_spec: from error
p_tyar_spec: from error
However, both Microsoft.Bcl.AsyncInterfaces, and System should contain IAsyncDisposable. What's causing the missing reference error?
I suspect its the assembly list is incomplete in some way, you can confirm this by altering the dynamic assembly generation function to the following:
checker.CompileToDynamicAssembly([input], "TestProject", allReferences, None, noframework = true)
noframework = true
Which works, (I just tested it)

Deserializing to enum option in F#

A couple days ago, I posted a question about deserialization with enums in F#.
The question is here: Deserialization in F# vs. C#
The answer pointed to some code written by Isaac Abraham, at: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e
However I am facing another problem:
If the object to deserialize to has an object of type 'enum option', the deserialization will fail, whereas it'll work if the type is just 'enum'.
A minimal example:
type TestType =
| A = 0
| B = 1
type TestObjectA =
{
test : TestType
}
type TestObjectB =
{
test : TestType option
}
let x = "{\"test\":\"A\"}"
let TestA = Deserialize<TestObjectA> x // will work
let TestB = Deserialize<TestObjectB> x // will fail
and the large deserialization code is at: https://pastebin.com/95JZLa6j
I put the whole code in a fiddle: https://dotnetfiddle.net/0Vc0Rh
but it can't be run from there since the F# version they support will not accept the 'object' keyword.
So, my question is: why can't I use the option type on an enum, but it works on other types? As a side note, since I'm quite new to F#, I'm not fully understanding Isaac's code, although I spent some time going through it and trying to troubleshoot it.
My understanding is that this line:
|> Seq.map (fun (value, propertyInfo) -> Convert.ChangeType(value, propertyInfo.PropertyType))
will try to convert the type to the right enum, but not to the enum option.
As a bonus question, is there a working solution that does full idiomatic deserialization with enums? (without going through null types)
open System.IO
type TestType =
| A = 0
| B = 1
type TestObjectB =
{
test : TestType option
}
let jsonSerializeToString obj =
use writer = new StringWriter()
let ser = new Newtonsoft.Json.JsonSerializer()
ser.Formatting <- Newtonsoft.Json.Formatting.Indented
ser.Serialize(writer, obj)
writer.ToString()
let jsonDeserializeFromString str =
Newtonsoft.Json.JsonConvert.DeserializeObject<TestObjectB>(str)
let Test obj =
let str = jsonSerializeToString obj
let obj' = jsonDeserializeFromString str
obj'
[<EntryPoint>]
let main argv =
{ test = Some TestType.B } |> Test |> ignore
{ test = None } |> Test |> ignore
0
Note: if you need to serialize a large collection of objects, then stream them to a file instead of an in-memory string to avoid an OutOfMemoryException. Like use writer = File.CreateText(filePath).
As a bonus question, is there a working solution that does full
idiomatic deserialization with enums?
I use the Microsoft.FsharpLu.Json package in production and find it works quite well for serializing and deserializing between "plain" javascript and idiomatic F#. Note Microsoft.FsharpLu.Json relies on Newtonsoft.Json under the hood.
Below is an example with your types and your test string, using Expecto for tests.
namespace FsharpLuJsonTest
open Newtonsoft.Json
open Microsoft.FSharpLu.Json
open Expecto
open Expecto.Flip
// Setup for FSharpLu.Json
type JsonSettings =
static member settings =
let s = JsonSerializerSettings(
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore)
s.Converters.Add(CompactUnionJsonConverter())
s
static member formatting = Formatting.None
type JsonSerializer = With<JsonSettings>
// Your example
type TestType =
| A = 0
| B = 1
type TestObjectA = { test : TestType }
type TestObjectB = { test : TestType option }
module Tests =
let x = """{"test":"A"}"""
[<Tests>]
let tests =
testList "Deserialization Tests" [
testCase "To TestObjectA" <| fun _ ->
JsonSerializer.deserialize x
|> Expect.equal "" { TestObjectA.test = TestType.A }
testCase "To TestObjectB" <| fun _ ->
JsonSerializer.deserialize x
|> Expect.equal "" { TestObjectB.test = Some TestType.A }
]
module Main =
[<EntryPoint>]
let main args =
runTestsInAssembly defaultConfig args
As you can see FsharpLu.Json supports Discriminated Unions and option types out of the box in the way you prefer. FsharpLu.Json is a less flexible solution than some others like Chiron (which allow for much more customisation) but I tend to prefer the opinionated approach of FsharpLu.Json.
I haven't used it personally, but the new FSharp.SystemText.Json library with the JsonUnionEncoding.ExternalTag setting should work roughly the same way FsharpLu.Json does. That library uses Microsoft's new System.Text.Json library under the hood rather than Newtonsoft.Json.

F# - How to call Moq ReturnsAsync()?

I have a function that returns Task<bool> (C#).
Task<bool> Update(MemberMarketUpdate memberMarketUpdate);
I'm trying to mock it using Moq (F#).
let verifyUpdate(update:MemberMarketUpdate) =
update.Id |> should equal "market id"
let setup = associationRepository.Setup (fun r -> r.Update(It.IsAny<MemberMarketUpdate>() ))
setup.Callback(fun update -> verifyUpdate update) |> ignore
//setup.Returns(Task.FromResult(True)) <- does not compile
//setup.ReturnsAsync(True) <- does not compile
I'm not able to use ReturnsAsync(True) to mock the Task<bool> result.
The error says:
No overloads match for method ReturnsAsync. The available overloads
are shown below.
(35 overloads here)
What is the correct syntax?
I tried to get your code to type check in a simple F# script file and the only thing I had to do to make it work was to change your upper-case True to lower-case true.
My complete script that type-checks fine, including all the necessary definitions and references looks like this:
#r #"packages\Moq\lib\net45\Moq.dll"
#r #"packages\NUnit\lib\net45\nunit.framework.dll"
#r #"packages\FsUnit\lib\net46\FsUnit.NUnit.dll"
#r #"packages\System.Threading.Tasks.Extensions\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll"
open Moq
open FsUnit
open System.Threading.Tasks
type MemberMarketUpdate =
{ Id: string }
type IAssociationRepository =
abstract Update : MemberMarketUpdate -> Task<bool>
let verifyUpdate(update:MemberMarketUpdate) =
update.Id |> should equal "market id"
let associationRepository = new Mock<IAssociationRepository>();
let setup = associationRepository.Setup (fun r -> r.Update(It.IsAny<MemberMarketUpdate>() ))
setup.Callback(fun update -> verifyUpdate update) |> ignore
setup.Returns(Task.FromResult(true))
setup.ReturnsAsync(true)
I am not that familiar with f# but try it all in one fluent call like the following, if possible.
associationRepository
.Setup(fun r -> r.Update(It.IsAny<MemberMarketUpdate>()))
.Callback(fun update -> verifyUpdate update)
.ReturnsAsync(True) |> ignore

How to execute module do block?

I need to do some setup in a module that I wanted to accomplish by leveraging a do block. Strangely though, my do block never seems to get hit.
Even stranger, If I load the module code into fsi, it does get hit. Here is my example:
Main.fs
[<EntryPoint>]
let main args =
printfn "%b" TestNamespace.M.x
0
TestModule.fs
namespace TestNamespace
module M =
do
printfn "In do"
failwith "Error" // this is line 6
let x = true
When I run the compiled executable I get
>test.exe
true
Why didn't the exception get thrown? If I run the module in FSI by itself I get
In do
System.Exception: Error
at <StartupCode$FSI_0006>.$FSI_0006.main#() in C:\Projects\Personal2\Playground\fsscripts\fsscripts\TestModule.fs:line 6
Stopped due to error
So it got the exception.
I see that in the decompliation that the do initializers get rolled into a seperate class
namespace \u003CStartupCode\u0024fsscripts\u003E
{
internal static class \u0024Library1
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
internal static int init\u0040;
static \u0024Library1()
{
ExtraTopLevelOperators.PrintFormatLine<Unit>((PrintfFormat<Unit, TextWriter, Unit, Unit>) new PrintfFormat<Unit, TextWriter, Unit, Unit, Unit>("In do"));
Operators.FailWith<Unit>("Error");
bool x = M.x;
}
}
}
VS the actual module code:
namespace TestNamespace
{
[CompilationMapping(SourceConstructFlags.Module)]
public static class M
{
public static bool x
{
[DebuggerNonUserCode] get
{
return true;
}
}
}
}
So how do I make sure the do block actually gets executed?
--
Edit, given the above example counts as a simple constant expression so won't produce an observable initialization, why does the following also not work?
[<EntryPoint>]
let main args =
printfn "%d" (TestNamespace.M.x id 1)
0
namespace TestNamespace
module M =
do
printfn "In do"
failwith "Error"
let x f a = f a
This prints out 1 no problem.
Edit, after having re-read Tomas's comments its because a function is considered a constant expression.
For a good explanation of the problem, see the answer to this previous SO question. The important bit says:
the static initializer for the file is executed on first access of a value that has observable initialization
Now, "observable initialization" is somewhat tricky idea, but simple constant initialization definitely does not have observable initialization - that's why the do block is not executed. You can trick the compiler into thinking that there is some imperative action, for example by adding do ():
module M =
do
printfn "In do"
failwith "Error" // this is line 6
let x = (do ()); true
You can get the behavior you want, while maintaining the same public interface, with a class:
type M private () =
static do
printfn "In do"
failwith "Error"
static member val x = true
Here is a clean way to do it.
First, note that if you wanted the initialization code to run every time the function is called, you would do this:
module M =
let init () =
printfn "In init"
let x f a =
init ()
printfn "In x"
f a
So, if you want it to be called just once (static initialization), you can simply remove the () from both places:
module M =
let init =
printfn "In init"
let x f a =
init
printfn "In x"
f a
The nice thing is that you have documented your design that the init code will be called first. If you have several separate blocks of initialization code, it is clear which dependency you are relying on (although the first initialization will execute all such blocks of course).
UPDATE
Here is a version, which works in a Release build too. Not quite so clean, but almost:
module Init =
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let call init = init
module M =
let init =
printfn "In init"
let x f a =
Init.call init
printfn "In x"
f a
Note that init is still a unit value, so Init.call is a non-inlined function that does nothing at all. So there is the overhead of a function call to nothing.
An alternative, which also works but seems a little strange is this:
module M =
let mutable init =
printfn "In init"
let x f a =
init <- init
printfn "In x"
f a
Can anyone improve on this?

Extending the Indexer for an existing class

Suppose I have type A with indexer implemented, e.g. type A is a library. Now I want to extend the indexer of it, e.g. here I want to add float number into the indexer.
I worked out the following code:
type A(a:int array) =
member this.Item
with get(x) = a.[x]
and set(x) value = a.[x] <- value
type A with
member m.Item with
get(x:float) = m.[x |> int]
and set(x:float) v = m.[x |> int] <- v
But it seems not working:
let a = A([| 1;2;3 |])
a.[1]
a.[1] <- 10
a.[1.0]
For the last line, I get:
Script1.fsx(243,4): error FS0001: This expression was expected to have type
int
but here has type
float
Is extending indexer possible in F#? Thanks!
This behaves differently when the type extension is defined in a separate assembly (or separate module) and when it is in the same module as the type definition.
When both are in the same module, F# compiles them into a single class and Item becomes a standard overloaded indexer - In this case, your code works as expected (and this is how you actually wrote it here).
When they are in separate modules, F# compiles the indexer as an extension member. In this case, I get the error message you described.
Adding new overloads using extension members (e.g. new method) is possible. As far I can see, the specificaton doesn't say that this shouldn't work for indexers, so I think it is a bug (can you report it to fsbugs at microsoft dot com?)
I just tried this in FSI and it seems to work.
What compiler are you using?
This is what I fed to FSI:
type A(a:int array) =
member this.Item
with get(x) = a.[x]
and set(x) value = a.[x] <- value
type A with
member m.Item
with get(x:float) = m.[x |> int]
and set(x:float) v = m.[x |> int] <- v
let a = A([| 1;2;3 |])
a.[1] <- 10
printfn "%A" a.[1.2]
This prints '10'

Resources