I'm a newbie to F# and I'm playing around with FParsec. I would use FParsec to generate an AST. I would like to use FsUnit to write some tests around the various parts of the parser to ensure correct operation.
I'm having a bit of trouble with the syntax (sorry, the exact code is at work, I can post a specific example later) so how exactly could one compare two discriminated unions (one the expected, the other the actual result)? Could someone provide a tiny code example using FsUnit (or NUnit), please?
An example discriminated union (very simple)
type AST =
| Variable of string
| Class of string
| Number of int
Since, as Brian pointed out, F# unions have structural equality, this is easy using whichever unit testing framework you are fond of.
FsUnit is an F# specific library built on top of NUnit. My personal favorite F# specific unit testing library is Unquote, ;), which is framework agnostic, working very well with NUnit, xUnit.net, MbUnit, ... or even within FSI. You may be interested in this comparison with FsUnit.
So, how would you do this with NUnit + Unquote? Here's a full working example:
module UnitTests
open NUnit.Framework
open Swensen.Unquote
type AST =
| Variable of string
| Class of string
| Number of int
let mockFParsec_parseVariable input = Variable(input)
[<Test>]
let ``test variable parse, passing example`` () =
test <# mockFParsec_parseVariable "x" = Variable("x") #>
[<Test>]
let ``test variable parse, failing example`` () =
test <# mockFParsec_parseVariable "y" = Variable("x") #>
Then running the tests using TestDriven.NET, the output is as follows:
------ Test started: Assembly: xxx.exe ------
Test 'UnitTests.test variable parse, failing example' failed:
UnitTests.mockFParsec_parseVariable "y" = Variable("x")
Variable "y" = Variable("x")
false
C:\xxx\UnitTests.fs(19,0): at UnitTests.test variable parse, failing example()
1 passed, 1 failed, 0 skipped, took 0.80 seconds (NUnit 2.5.10).
An example - if you want to check the type but not the contents
let matched x=
match x with
|Variable(_) -> true
| _ -> false
Note here that you need a different function for each element of the discriminated union
If you want to compare equality, you can just do it in the standard way, like
Assert.AreEqual(Variable("hello"),result)
or
if result = Variable("hello") then stuff()
Related
The following code is from chapter 5 of "F# 4.0 Design Patterns".
let a = 1,"car"
type System.Tuple<'T1,'T2> with
member t.AsString() =
sprintf "[[%A]:[%A]]" t.Item1 t.Item2
(a |> box :?> System.Tuple<int,string>).AsString()
The desired output is [[1]:["car"]]
However, a red squiggly appears under AsString(). "The field, constructor or member 'AsString' is not defined. Maybe you want one of the following: ToString"
This is a bit odd code sample - I suspect the point that this is making is that F# tuples are actually .NET tuples represented using System.Tuple - by showing that an extension to System.Tuple can be invoked on ordinary F# tuples.
I suspect the behaviour of F# has changed and it no longer allows this - it may have been that adding extensions was allowed on System.Tuple, but not on ordinary F# tuples, but the two have became more unified in the compiler.
However, you can do a very similar thing using the .NET-style extension methods:
let a = 1,"car"
[<System.Runtime.CompilerServices.ExtensionAttribute>]
type TupleExtensions =
[<System.Runtime.CompilerServices.ExtensionAttribute>]
static member AsString(t:System.Tuple<'T1,'T2>) =
sprintf "[[%A]:[%A]]" t.Item1 t.Item2
let st = (a |> box :?> System.Tuple<int,string>)
st.AsString()
This can actually be also invoked directly on an F# tuple value:
("car", 32).AsString()
How do functional programmers test functions that return a unit?
In my case, I believe I need to unit test an interface to this function:
let logToFile (filePath:string) (formatf : 'data -> string) data =
use file = new System.IO.StreamWriter(filePath)
file.WriteLine(formatf data)
data
What is the recommended approach when I'm unit testing a function with I/O?
In OOP, I believe a Test Spy can be leveraged.
Does the Test Spy pattern translate to functional programming?
My client looks something like this:
[<Test>]
let ``log purchase``() =
[OneDollarBill] |> select Pepsi
|> logToFile "myFile.txt" (sprintf "%A")
|> should equal ??? // IDK
My domain is the following:
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 }
Do not see this as an authoritative answer, because I'm not an expert on testing, but my answer to this question would be that, in a perfect world, you cannot and do not need to test unit-returning functions.
Ideally, you would structure your code so that it is composed from some IO to read data, transformations encoding all the logic and some IO to save the data:
read
|> someLogic
|> someMoreLogic
|> write
The idea is that all your important things are in someLogic and someMoreLogic and that read and write are completely trivial - they read file as string or sequence of lines. This is trivial enough that you do not need to test it (now, you could possibly test the actual file writing by reading the file back again, but that's when you want to test the file IO rather than any logic that you wrote).
This is where you would use a mock in OO, but since you have a nice functional structure, you would now write:
testData
|> someLogic
|> someMoreLogic
|> shouldEqual expectedResult
Now, in reality, the world is not always that nice and something like a spy operation ends up being useful - perhaps because you are interoperating with a world that is not purely functional.
Phil Trelford has a nice and very simple Recorder that lets you record calls to a function and check that it has been called with the expected inputs - and this is something I've found useful a number of times (and it is simple enough that you do not really need a framework).
Obviously, you could use a mock as you would in imperative code as long as the unit of code takes its dependencies as a parameter.
But, for another approach, I found this talk really interesting Mocks & stubs by Ken Scambler. As far as I recall the general argument was that you should avoid using mocks by keeping all functions as pure as possible, making them data-in-data-out. At the very edges of your program, you would have some very simple functions that perform the important side-effects. These are so simple that they don't even need testing.
The function you provided is simple enough to fall into that category. Testing it with a mock or similar would just involve ensuring that certain methods are called, not that the side-effect occurred. Such a test isn't meaningful and doesn't add any value over the code itself, while still adding a maintenance burden. It's better to test the side-effect part with an integration test or end-to-end test that actually looks at the file that was written.
Another good talk on the subject is Boundaries by Gary Bernhardt which Discusses the concept of Functional Core, Imperative Shell.
I am trying to test that the return result from an F# function matches an expected discriminated union case. I am using NUnit to create the tests and it does not like the discriminated union type as a TestCase parameter. The following test case fails to compile:
[<TestCase("RF000123", Iccm.CallType.Request)>]
let ``callTypeFromCallNumber returns expected call type``
callNumber callType =
test <# Iccm.callTypeFromCallNumber callNumber = callType #>
I expect that this is a limitation of NUnit but I am not completely sure. I have an idea to work around this which I will post as my answer but a more elegant solution will be nice.
How can I use a discriminated union case as a test case attribute parameter?
This isn't a limitation of NUnit, but of the F# language (as well as C# and VB): You can only put constants into attributes, but not objects. Discriminated Unions compile to objects in IL, so you can't put them into attributes.
You can put enums into attributes, though, since they're constants (they're numbers at run-time).
From the example in the OP, it looks like the CallType Discriminated Union has no associated data, so you could consider changing the design to an enum instead:
type CallType =
| Request = 0
| Incident = 1
| ChangeManagement = 2
| Unknown = 3
You should realise, though, that that makes CallType an enum; it's no longer a Discriminated Union. It should enable you to use the values in attributes, though.
Here is my workaround to the problem. It works just fine although I find it a little bit make shift. I just use strings in place of the types and then pattern match to convert to the actual type in the assertion.
[<TestCase("RF000123", "Request")>]
[<TestCase("IM000123", "Incident")>]
[<TestCase("CM000123", "ChangeManagement")>]
[<TestCase("AR000123", "Unknown")>]
let ``callTypeFromCallNumber returns expected call type``
callNumber callType =
test <# Iccm.callTypeFromCallNumber callNumber = match callType with
| "Request" -> Iccm.CallType.Request
| "Incident" -> Iccm.CallType.Incident
| "ChangeManagement" -> Iccm.CallType.ChangeManagement
| _ -> Iccm.CallType.Unknown #>
I've been writing some F# now for about 6 months and I've come across some behavior that I can't explain. I have some boiled down code below. (value names have been changed to protect the innocent!)
I have a hierarchy defined using record types rec1 and rec2, and also a dicriminated union type with possible values CaseA and CaseB. I'm calling a function ('mynewfunc') that takes a du_rec option type. Internally this function defines a recursive function that processes the hierarchy .
I'm kicking off the processing by passing the None option value to represent the root of the hierarchy (In reality, this function is deserializing the hierarchy from a file).
When I run the code below I hit the "failwith "invalid parent"" line of code. I can not understand why this is, because the None value that is passed down should match the outer pattern matching's None case.
The code works if I delete either of the sets of comments. This is not a showstopper for me - I just feel a bit uncomfortable not knowing why this is happening (I thought I was understanding f#)
Thanks in advance for any replies
James
type rec2 =
{
name : string
child : rec1 option
}
and rec1 =
{
name : string ;
child : rec2 option
}
and du_rec =
| Case1 of rec1
| Case2 of rec2
let mynewfunc (arg:du_rec option) =
let rec funca (parent:du_rec option) =
match parent with
| Some(node) ->
match node with
| Case2(nd) ->
printfn "hello"
(* | Case1(nd) ->
printfn "bye bye" *)
| _ ->
failwith "invalid parent"
| None ->
// printfn "case3"
()
funcb( None )
and funcb (parent: du_rec option) =
printfn "this made no difference"
let node = funca(arg)
()
let rootAnnot = mynewfunc(None)
Based on the comments, this is just a bad experience in the debugger (where the highlighting suggests that the control flow is going places it is not); the code does what you expect.
(There are a number of places where the F# compiler could improve its sequence-points generated into the pdbs, to improve the debugging experience; I think we'll be looking at this in a future release.)
So, by a hilarious series of events, I downloaded the FParsec source and tried to build it. Unfortunately, it's not compatible with the new 1.9.9.9. I fixed the easy problems, but there are a couple of discriminated unions that still don't work.
Specifically, Don Syme's post explains that discriminated unions containing items of type obj or -> don't automatically get equality or comparison constraints, since objects don't support comparison and functions don't support equality either. (It's not clear whether the automatically generated equality/comparison was buggy before, but the code won't even compile now that they're no longer generated.)
Here are some examples of the problematic DUs:
type PrecedenceParserOp<'a,'u'> =
| PrefixOp of string * Parser<unit,'u> * int * bool * ('a -> 'a)
| others ...
type ErrorMessage =
| ...
| OtherError of obj
| ...
Here are the offending uses:
member t.RemoveOperator (op: PrecedenceParserOp<'a, 'u>) =
// some code ...
if top.OriginalOp <> op then false // requires equality constraint
// etc etc ...
or, for the comparison constraint
let rec printMessages (pos: Pos) (msgs: ErrorMessage list) ind =
// other code ...
for msg in Set.ofList msgs do // iterate over ordered unique messages
// etc etc ...
As far I can tell, Don's solution of tagging each instance with a unique int is the Right Way to implement a custom equality/comparison constraint (or a maybe a unique int tuple so that individual branches of the DU can be ordered). But this is inconvenient for the user of the DU. Now, construction of the DU requires calling a function to get the next stamp.
Is there some way to hide the tag-getting and present the same constructors to users of the library? That is, to change the implementation without changing the interface? This is especially important because it appears (from what I understand of the code) that PrecedenceParserOp is a public type.
What source did you download for FParsec? I grabbed the latest from the FParsec BitBucket repository, and I didn't have to make any changes at all to the FParsec source to get it to compile in VS 2010 RC.
Edit: I take that back. I did get build errors from the InterpLexYacc and InterpFParsec sample projects, but the core FParsec and FParsecCS projects build just fine.
One thing you could do is add [<CustomEquality>] and [<CustomComparison>] attributes and define your own .Equals override and IComparable implementation. Of course, this would require you to handle the obj and _ -> _ components yourself in an appropriate way, which may or may not be possible. If you can control what's being passed into the OtherError constructor, you ought to be able to make this work for the ErrorMessage type by downcasting the obj to a type which is itself structurally comparable. However, the PrecendenceParserOp case is a bit trickier - you might be able to get by with using reference equality on the function components as long as you don't need comparison as well.