Using assertion messages with Unquote in F#? - f#

Some test assertion frameworks allow you to add a custom message to your assertion, such as the following using NUnit:
Assert.AreEqual(1, result, "the result should be one")
Is it possible to do the same when using Unquote in F#?
test <# result = 1 #>
Update
The closest I have got to this is to add a simple comment inside the quoted expression. As my motivation for this was to document what is being verified (I tend to assert more than once!), this is quite adequate for my needs.
test <#
// the result should be one
result = 1
#>
Another Update
I've been using Stephen's suggestion to use ignore "description here";, which I really like. I find it easier to read if I declare my own function like so:
> let inline checking _ = ()
> let result = 2;;
> test <# checking "the result should be one"; result = 1 #>;;
Test failed:
checking "the result should be one"; result = 1
(); result = 1
result = 1
2 = 1
false

You could do something like this (using F# Interactive)
> let result = 2;;
> test <# ignore "the result should be one"; result = 1 #>;;
Test failed:
ignore "the result should be one"; result = 1
(); result = 1
result = 1
2 = 1
false
But if you use variable names like expected and actual, Unquote's output can be rich enough to obviate the need for such supplementary comments
> let actual = 2;;
> let expected = 1;;
> test <# actual = expected #>;;
Test failed:
actual = expected
2 = 1
false

Related

Can I know the actual expression that failed in Xunit?

Suppose I have a test using Xunit like this:
module Tests
open System
open Xunit
let isSquare x =
let root = sqrt x
root % 1 = 0
[<Fact>]
let ``Various tests`` () =
let whitelist =
[
1
4
9
9481129 // Will trigger failure
16
25
]
for x in whitelist do
Assert.True (isSquare x)
let blacklist =
[
3
26
101
]
for x in blacklist do
Assert.False (isSquare x)
When I run this test, the failure message is not very useful:
[xUnit.net 00:00:00.98] ... Error Message:
Assert.False() Failure
Expected: False
Actual: True
Stack Trace: ...
It gives me the line number of the assert, but what I actually want is the value of x where it failed.
Ideally something like this:
Assertion failed for:
Assert.True (isSquare 9481129)
Is it possible to do this with Xunit, even with long or generated white/black lists?
My current work-around is to add print statements, which is not ideal.
Have you considered using a Theory instead?
[<Theory>]
[<InlineData(1)>]
[<InlineData(4)>]
[<InlineData(9)>]
[<InlineData(9481129)>]
[<InlineData(16)>]
[<InlineData(25)>]
let ``Is square`` num =
Assert.True (isSquare num)
The test runner would then show you which cases cause the test to fail:
Tests.Is square(num: 9481129) [FAIL]
Assert.True() Failure
Expected: True
Actual: False
Stack Trace: ...
Assert.True takes a second optional parameter - a string representing the message that would be printed. You can use that to generate whatever messages you want:
for x in whitelist do
Assert.True(isSquare x, sprintf "Apparently %d is not a square" x)

How to test F# option types with xUnit

I want to unit test this bit of code using xUnit in F#. How do I handle the options?
From Scott Wlaschin's book: Domain Modeling Made Functional
type UnitQuantity = private UnitQuantity of int
// ^ private constructor
// define a module with the same name as the type
module UnitQuantity =
/// Define a "smart constructor" for UnitQuantity
/// int -> Result<UnitQuantity,string>
let create qty =
if qty < 1 then
// failure
Error "UnitQuantity can not be negative"
else if qty > 1000 then
// failure
Error "UnitQuantity can not be more than 1000"
else
// success -- construct the return value
Ok (UnitQuantity qty)
Test:
let ``Check UnitQuantity.create is one`` () =
// ARRANGE
let expected = 1
// ACT
//let unitQtyResult = UnitQuantity.create 1
match UnitQuantity.create 1 with
| Error msg -> 0
//printfn "Failure, Message is %s" msg
| Ok x -> 0
// let innerValue = UnitQuantity.value actual
// ASSERT
//Assert.Equal(expected,actual)
I know the ACT is all wrong, that is where I am hung up. I do not understand F# options nor xUnit.net nor unit testing enough yet to Assert on the actual value from the function.
I'd probably compare the result directly rather than pattern matching. However, you can't create an Ok result for Result<UnitQuantity, string> because of the private constructor.
You can use the built-in Result.map to map the Ok value of a result. Using UnitQuantity.value you can map from Result<UnitQuantity, string> to Result<int, string>. So this should work:
let expected = Ok 1
let actual = UnitQuantity.create 1 |> Result.map UnitQuantity.value
Assert.Equal(expected, actual)
A general rule of thumb with unit tests is that the Act section should be a single statement.
Everything that we want to check about the result is some form of assertion
So we want to assert whether the result is either an Ok<UnitQuantity> or an Error<string>.
This is where pattern matching allows us to test this very succintly
let ``Check UnitQuantity.create is one`` () =
// ARRANGE
let qty = 1 // The quantity we supply is one
let expected = qty // We expect to get that value back
// ACT
let actual = UnitQuantity.create qty
// ASSERT
// Check if we have an Ok or an Error
match actual with
| Ok unitQuantity ->
// If Ok, check the value is what we expect
let innerValue = UnitQuantity.value unitQuantity
Assert.Equal(innerValue, expected)
// If Error raise an AssertException to fail the test
| Error errorMessage ->
let error = sprintf "Expected Ok, was Error(%s)." errorMessage
Assert.True(false, error) // Force an assertion failure with our error message
Note the UnitQuantity.value method, it' a simple unwrap function you can add to the end of the UnitQuantity module that will give you back the int value so you can easily compare it
let value (UnitQuantity e) = e
If you wanted to test an option type, it would be very similar, using a match statement like so
match actual with
| Some value ->
// Do your assertions here
()
| None ->
// Do your assertions here
()
Faced with a similar problem, I decided I wasn't so concerned with checking the value itself, but with checking the behavior above and below the threshold. I decided to verify the result is Ok if the value is in range and an Error outside the range.
type UnitQuantity = private UnitQuantity of int
module UnitQuantity =
let min = 1
let max = 1000
let create qty =
if qty < min then
Error $"UnitQuantity cannot be less than {min}"
else if qty > max then
Error $"UnitQuantity cannot be more than {max}"
else
Ok (UnitQuantity qty)
module Tests =
let min = 1
let max = 1000
let shouldBeError = function
| Error _ -> ()
| _ -> failwith "is not error"
let shouldBeOk = function
| Ok _ -> ()
| _ -> failwith "is not Ok"
[<Fact>]
let ``create unit qty at min`` () =
UnitQuantity.create min |> shouldBeOk
[<Fact>]
let ``create unit qty below min`` () =
UnitQuantity.create (min - 1) |> shouldBeError
[<Fact>]
let ``create unit qty at max`` () =
UnitQuantity.create max |> shouldBeOk
[<Fact>]
let ``create unit qty above max`` () =
UnitQuantity.create (max + 1) |> shouldBeError

Ternary operator to choose an Array index

Unexpected ']' in expression
I have successfully managed to get the first part of the code working and now want to find the players real score using the index stored inside the member. I am using playersTurn and checking if its odd or even to represent the players turn.
The issue I am having now is using a ternary operator to get the score in the following line of code:
let score = this.scoring[this.playersTurn % 2 = 0 ? this.playerOneScore : this.playerTwoScore]
Any help would be brilliant, here is the full code:
open System
type Game(playerOne, playerTwo) =
member this.playersTurn = 0
member this.playerOneName = playerOne
member this.playerOneScore = 0
member this.playerTwoName = playerTwo
member this.playerTwoScore = 0
member this.scoring = [|0; 15; 30; 40|]
member this.takeTurn() =
let name = this.playersTurn % 2 = 0 ? this.playerOneName : this.playerTwoName
let score = this.scoring[this.playersTurn % 2 = 0 ? this.playerOneScore : this.playerTwoScore]
printfn name |> "%d is now taking their turn."
if((new System.Random()).Next(0, 15) > 8) then
if (this.playersTurn % 2 = 0) then incr this.playerOneScore
else incr this.playerTwoScore
printfn name |> "%d scored a point!"
else
printfn name |> "%d did not score a point!"
incr this.playersTurn
let tennis = new Game("Player1", "Player2")
tennis.takeTurn()
tennis.takeTurn()
To make the code work, you'll need to do a few more changes. Most importantly, you are using class with members, but those are read-only getter properties in F#. You could make them mutable, but that's not idiomatic; better option is to change the function so that it returns the new game state.
If you are learning F#, then I think it's better to make more changes and avoid using classes (they are not used that frequently in F#) and also go for a solution that does not need mutation. The following is close to what you had.
I extracted the common definitions into ordinary let values - you can later define a record (simple data type) to keep them, but for now, this is the easiest option:
open System
let scoring = [|0; 15; 30; 40|]
let playerOne = "Player1"
let playerTwo = "Player2"
let rnd = new System.Random()
I turned your method into a function that takes number of turns and initial scores as a tuple and returns new state. The syntax (playersTurn, (playerOneScore, playerTwoScore)) defines a tuple with number of turns and a nested tuple with the two scores (I choose this because the two scores are logically related, so it's nice to store them together):
let takeTurn (playersTurn, (playerOneScore, playerTwoScore)) =
let name = if playersTurn % 2 = 0 then playerOne else playerTwo
let score = scoring.[if playersTurn % 2 = 0 then playerOneScore else playerTwoScore]
printfn "%s is now taking their turn." name
let newOneScore, newTwoScore =
if (rnd.Next(0, 15) > 8) then
printfn "%s scored a point!" name
if (playersTurn % 2 = 0) then playerOneScore + 1, playerTwoScore
else playerOneScore, playerTwoScore + 1
else
printfn "%s did not score a point!" name
playerOneScore, playerTwoScore
playersTurn+1, (newOneScore, newTwoScore)
Now you can define an initial state and call takeTurn repeatedly to get the next state (and the next state and so on):
let start = 0, (0, 0)
let step1 = takeTurn start
let step2 = takeTurn step1
You'll obviously want to run this in a loop - which you can do in the functional way using recursion, or using a function such as Seq.unfold.
You're using the C# syntax for a ternary operator in F#. You really need:
this.scoring.[if this.playersTurn % 2 = 0 then this.playerOneScore else this.playerTwoScore]

How do I retrieve a value from a composite generic type?

How do I retrieve a value from a generic?
Specifically, I am attempting the following:
// Test
let result = Validate goodInput;;
// How to access record??
let request = getRequest result
Here's the code:
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
let bind nextFunction lastFunctionResult =
match lastFunctionResult with
| Success input -> nextFunction input
| Failure f -> Failure f
type Request = {name:string; email:string}
let validate1 input =
if input.name = "" then Failure "Name must not be blank"
else Success input
let validate2 input =
if input.name.Length > 50 then Failure "Name must not be longer than 50 chars"
else Success input
let validate3 input =
if input.email = "" then Failure "Email must not be blank"
else Success input;;
let Validate =
validate1
>> bind validate2
>> bind validate3;;
// Setup
let goodInput = {name="Alice"; email="abc#abc.com"}
let badInput = {name=""; email="abc#abc.com"};;
// I have no clue how to do this...
let getRequest = function
| "Alice", "abc#abc.com" -> {name="Scott"; email="xyz#xyz.com"}
| _ -> {name="none"; email="none"}
// Test
let result = Validate goodInput;;
// How to access record??
let request = getRequest result
printfn "%A" result
You mean how do you extract the record out of your result type? Through pattern matching, that's what you're already doing in bind.
let getRequest result =
match result with
| Success input -> input
| Failure msg -> failwithf "Invalid input: %s" msg
let result = Validate goodInput
let record = getRequest result
This will return the record or throw an exception. Up to you how you handle the success and failure cases once you have your Result - that could be throwing an exception, or turning it into option, or logging the message and returning a default etc.
This seems to be a frequently asked question: How do I get the value out of a monadic value? The correct answer, I believe, is Mu.
The monadic value is the value.
It's like asking, how do I get the value out of a list of integers, like [1;3;3;7]?
You don't; the list is the value.
Perhaps, then, you'd argue that lists aren't Discriminated Unions; they have no mutually exclusive cases, like the above Result<'TSuccess,'TFailure>. Consider, instead, a tree:
type Tree<'a> = Node of Tree<'a> list | Leaf of 'a
This is another Discriminated Union. Examples include:
let t1 = Leaf 42
let t2 = Node [Node []; Node[Leaf 1; Leaf 3]; Node[Leaf 3; Leaf 7]]
How do you get the value out of a tree? You don't; the tree is the value.
Like 'a option in F#, the above Result<'TSuccess,'TFailure> type (really, it's the Either monad) is deceptive, because it seems like there should only be one value: the success. The failure we don't like to think about (just like we don't like to think about None).
The type, however, doesn't work like that. The failure case is just as important as the success case. The Either monad is often used to model error handling, and the entire point of it is to have a type-safe way to deal with errors, instead of exceptions, which are nothing more than specialised, non-deterministic GOTO blocks.
This is the reason the Result<'TSuccess,'TFailure> type comes with bind, map, and lots of other goodies.
A monadic type is what Scott Wlaschin calls an 'elevated world'. While you work with the type, you're not supposed to pull data out of that world. Rather, you're supposed to elevate data and functions up to that world.
Going back to the above code, imagine that given a valid Request value, you'd like to send an email to that address. Therefore, you write the following (impure) function:
let send { name = name; email = email } =
// Send email using name and email
This function has the type Request -> unit. Notice that it's not elevated into the Either world. Still, you want to send the email if the request was valid, so you elevate the send method up to the Either world:
let map f = bind (fun x -> Success (f x))
let run = validate1 >> bind validate2 >> bind validate3 >> map send
The run function has the type Request -> Result<unit,string>, so used with goodInput and badInput, the results are the following:
> run goodInput;;
val it : Result<unit,string> = Success unit
> run badInput;;
val it : Result<unit,string> = Failure "Name must not be blank"
And then you probably ask: and how do I get the value out of that?
The answer to that question depends entirely on what you want to do with the value, but, imagine that you want to report the result of run back to the user. Displaying something to the user often involves some text, and you can easily convert a result to a string:
let reportOnRun = function
| Success () -> "Email was sent."
| Failure msg -> msg
This function has the type Result<unit,string> -> string, so you can use it to report on any result:
> run goodInput |> reportOnRun;;
val it : string = "Email was sent."
> run badInput |> reportOnRun;;
val it : string = "Name must not be blank"
In all cases, you get back a string that you can display to the user.

Function to return another function's body

Is there a way in F# to create a function that takes any other function as its sole parameter and return that function's body text as the result?
For example:
let myFunc =
// Always equals 3!
let x = 1 + 2
// Print it to the console
printfn "x = %i" x
let extractFunctionText f =
???
extractFunctionText myFunc
extractFunctionText should have a signature of ('a -> 'b) -> string i.e. it will take any function as an input and returns a string. The string I'd like returned in the last line of specific example above is:
"""// Always equals 3!
let x = 1 + 2
// Print it to the console
printfn "x = %i" x"""
Apologies for any typos or naive questions: I'm a bit of a newb at this. I think that following links (SO Answer & MSDN) get me quite close but I don't understand things well enough to finish the job

Resources