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)
Related
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
I have a two-level F# / Argu command tree. Its abbreviated version looks like that:
[<CliPrefix(CliPrefix.Dash)>]
type RunContGenArgs =
| [<Unique>] [<EqualsAssignment>] [<AltCommandLine("-ql")>] MaxQueueLength of int
with
interface IArgParserTemplate with
member this.Usage =
match this with
| MaxQueueLength _ -> "max queue length."
and
[<CliPrefix(CliPrefix.None)>]
ContGenArguments =
| [<Unique>] [<AltCommandLine("run")>] RunContGen of ParseResults<RunContGenArgs>
with
interface IArgParserTemplate with
member this.Usage =
match this with
| RunContGen _ -> "run Continuous Generation."
which, I then use as follows:
[<EntryPoint>]
let main argv =
let parser = ArgumentParser.Create<ContGenArguments>(programName = "ContGen.exe")
let results = parser.Parse argv
match results.GetAllResults() |> ContGenTask.tryCreate with
| Some task -> task.run()
| None ->
printfn "%s" (parser.PrintUsage())
-1
If I run the command like ContGen.exe run help, then it correctly displays help for the command run. However, it then crashes with ugly exception:
Unhandled Exception: Argu.ArguParseException: USAGE: ContGen.exe runcontgen [help] [-maxqueuelength=<int>]
OPTIONS:
-maxqueuelength, -ql=<int>
max queue length.
help display this list of options.
at Argu.ExceptionExiter.Argu-IExiter-Exit[a](String msg, ErrorCode errorCode) in C:\Users\eirik.tsarpalis\devel\public\Argu\src\Argu\Types.fs:line 62
at Argu.ArgumentParser\`1.Parse(FSharpOption\`1 inputs, FSharpOption\`1 configurationReader, FSharpOption\`1 ignoreMissing, FSharpOption\`1 ignoreUnrecognized, FSharpOption\`1 raiseOnUsage) in C:\Users\eirik.tsarpalis\devel\public\Argu\src\Argu\ArgumentParser.fs:line 180
at Program.main(String[] argv) in C:\GitHub\ClmFSharp\Clm\ContGen\Program.fs:line 8
If I change let results = parser.Parse argv into let results = parser.Parse(argv, raiseOnUsage = false), then it does not crash but does not display any help message. And then since command run can run without any second level argument, the program just keeps going instead of displaying help and quitting.
However, I need ContGen.exe run help just display help message and then quit. How can I achieve that? Thanks.
This is a somewhat peculiar behavior of Argu; you need to provide your own exiter to avoid the exception being thrown there.
Something along these lines:
type NonThrowingExiter() =
interface IExiter with
member __.Name = "Exiter" // I don't know what this is used for; I have never seen it appear anywhere
member __.Exit (msg, code) =
if code = ErrorCode.HelpText then
printfn "%s" msg
exit 0
else
printfn "%s" msg // Maybe have code to color the console output red here
exit 1
To use this, create your `ArgumentParser` like this:
let argumentParser =
Argu.ArgumentParser.Create<ContGenArguments>(helpTextMessage = "Help requested",
errorHandler = NonThrowingExiter())
(You don't actually need to create a class for this, of course; an object expression will do it just as well.)
I am trying to use DotCover in FAKE , but it is throwing some error , as I am new to FAKE as well as F# , it's becoming difficult for me to understand the root cause of the problem . Here is the code :
#r "D:/FAKEProject/Fake/packages/FAKE/tools/FakeLib.dll"
open Fake
open Fake.DotCover
let testDir = "D:/FAKEProject/Fake/test/"
let filters = ""
Target "Clean" (fun _ ->
CleanDirs [testDir]
)
Target "TestCoverage" (fun _ ->
!! ("D:/FAKEProject/Fake/UnitTest/UnitTest.dll")
|> DotCoverNUnit
(fun p -> { p with Output = testDir ## "NUnitDotCover.snapshot"
ToolPath = "D:/tools/dotCover/dotCover.exe"
Filters = filters })
(fun nunitOptions -> nunitOptions)
)
"Clean"
==> "TestCoverage"
RunTargetOrDefault "TestCoverage"`
It is giving this error
System.Exception: Error running D:/tools/dotCover/dotCover.exe with exitcode -1
at Fake.DotCover.buildParamsAndExecute#124-6.Invoke(String message) in C:\code\fake\src\app\FakeLib\DotCover.fs:line 124
at Fake.DotCover.buildParamsAndExecute[a](a parameters, FSharpFunc`2 buildArguments, String toolPath, String workingDir, Boolean failBuild) in C:\code\fake\src\app\FakeLib\DotCover.fs:line 124
at Fake.DotCover.DotCoverNUnit(FSharpFunc`2 setDotCoverParams, FSharpFunc`2 setNUnitParams, IEnumerable`1 assemblies) in C:\code\fake\src\app\FakeLib\DotCover.fs:line 190
at FSI_0005.DotCover.clo#16-2.Invoke(Unit _arg2) in D:\FAKEProject\Fake\DotCover.fsx:line 17
at Fake.TargetHelper.runSingleTarget(TargetTemplate`1 target) in C:\code\fake\src\app\FakeLib\TargetHelper.fs:line 492`
I am not able to understand why it is searching in C:\code\fake\src\app\fakelib\dotcover.fs
and what is dotcover.fs it is looking for
How to solve this problem , as I am stuck at this error , If anyone can help me regarding this , it would be very helpful .
Thank You
The mysterious C:\code\fake\src\app\FakeLib\DotCover.fs line is simply telling you the filename (and line number) of the source file that threw the error. Not the filename on your system, but the filename on the system where your FAKE.exe file was built. In other words, it's just telling you where the exception was thrown from.
Looking at the FAKE source code, I see that line 124 is near the end of the following block of code:
let buildParamsAndExecute parameters buildArguments toolPath workingDir failBuild =
let args = buildArguments parameters
trace (toolPath + " " + args)
let result = ExecProcess (fun info ->
info.FileName <- toolPath
info.WorkingDirectory <- getWorkingDir workingDir
info.Arguments <- args) TimeSpan.MaxValue
let ExitCodeForFailedTests = -3
if (result = ExitCodeForFailedTests && not failBuild) then
trace (sprintf "DotCover %s exited with errorcode %d" toolPath result)
else if (result = ExitCodeForFailedTests && failBuild) then
failwithf "Failing tests, use ErrorLevel.DontFailBuild to ignore failing tests. Exited %s with errorcode %d" toolPath result
else if (result <> 0) then
failwithf "Error running %s with exitcode %d" toolPath result
else
trace (sprintf "DotCover exited successfully")
The failwithf function is F#'s equivalent of "throw new Exception()", but it lets you specify a message (using printfn-style format codes like %s) to go with the exception. So there's nothing mysterious going on here in F#, it's just that your D:/tools/dotCover/dotCover.exe program has returned a -1 return code. Return codes of -1 usually mean "generic error", so that's not much help in figuring out the cause.
Your next troubleshooting step is to run your dotCover.exe program manually, giving it the same arguments that FAKE is giving it (shouldn't be too hard to figure out, since the FAKE option records are usually pretty well-named) and the same input. Then see what error messages, if any, dotCover.exe is printing out before it fails.
There is any way to do it like C/C#?
For example (C# style)
for (int i = 0; i < 100; i++)
{
if (i == 66)
break;
}
The short answer is no. You would generally use some higher-order function to express the same functionality. There is a number of functions that let you do this, corresponding to different patterns (so if you describe what exactly you need, someone might give you a better answer).
For example, tryFind function returns the first value from a sequence for which a given predicate returns true, which lets you write something like this:
seq { 0 .. 100 } |> Seq.tryFind (fun i ->
printfn "%d" i
i=66)
In practice, this is the best way to go if you are expressing some high-level logic and there is a corresponding function. If you really need to express something like break, you can use a recursive function:
let rec loop n =
if n < 66 then
printfn "%d" n
loop (n + 1)
loop 0
A more exotic option (that is not as efficient, but may be nice for DSLs) is that you can define a computation expression that lets you write break and continue. Here is an example, but as I said, this is not as efficient.
This is really ugly, but in my case it worked.
let mutable Break = false
while not Break do
//doStuff
if breakCondition then
Break <- true
done
This is useful for do-while loops, because it guarantees that the loop is executed at least once.
I hope there's a more elegant solution. I don't like the recursive one, because I'm afraid of stack overflows. :-(
You have to change it to a while loop.
let (i, ans) = (ref 0, ref -1)
while(!i < 100 and !ans < 0) do
if !i = 66 then
ans := !i
ans
(This breaks when i gets to 66--but yes the syntax is quite different, another variable is introduced, etc.)
seq {
for i = 0 to 99 do
if i = 66 then yield ()
}
|> Seq.tryItem 0
|> ignore
Try this:
exception BreakException
try
for i = 0 to 99 do
if i = 66 then
raise BreakException
with BreakException -> ()
I know that some folks don't like to use exceptions. But it has merits.
You don't have to think about complicated recursive function. Of
cause you can do that, but sometimes it is unnecessarily bothersome
and using exception is simpler.
This method allows you to break at halfway of the loop body. (Break "flag" method is simple too but it only allows to break at the end of the loop body.)
You can easily escape from nested loop.
For these kind of problems you could use a recursive function.
let rec IfEqualsNumber start finish num =
if start = finish then false
elif
start = num then true
else
let start2 = start + 1
IfEqualsNumber start2 finish num
Recently I tried to solve a similar situation:
A list of, say, 10 pieces of data. Each of them must be queried against a Restful server, then get a result for each.
let lst = [4;6;1;8]
The problem:
If there is a failed API call (e.g. network issue), there is no point making further calls as we need all the 10 results available. The entire process should stop ASAP when an API call fails.
The naive approach: use List.map()
lst |> List.map (fun x ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
sqlComd.ExecuteScala() |> Some
with
| :? System.Data.SqlClient.SqlException as ex -> None
)
But as said, it's not optimal. When a failed API occurs, the remaining items keep being processed. They do something that is ignored at the end anyway.
The hacky approach: use List.tryFindIndex()
Unlike map(), we must store the results somewhere in the lamda function. A reasonable choice is to use mutable list. So when tryFindIndex() returns None, we know that everything was ok and can start making use of the mutable list.
val myList: List<string>
let res = lst |> List.tryFindIndex (fun x ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
myList.Add(sqlComd.ExecuteScala())
false
with
|:? System.Data.SqlClient.SqlException as ex -> true
)
match res with
| Some _ -> printfn "Something went wrong"
| None -> printfn "Here is the 10 results..."
The idiomatic approach: use recursion
Not very idiomatic as it uses Exception to stop the operation.
exception MyException of string
let makeCall lstLocal =
match lstLocal with
| [] -> []
| head::tail ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
let temp = sqlComd.ExecuteScala()
temp :: makeCall (tail)
with
|:? System.Data.SqlClient.SqlException as ex -> raise MyException ex.Message
try
let res = makeCall lst
printfn "Here is the 10 results..."
with
| :? MyException -> printfn "Something went wrong"
The old-fashion imperative approach: while... do
This still involves mutable list.
I have written two versions of code. The first one works as expected and print "Hi". the second one gives me error that "block following this let is unfinished"
1st version
#light
let samplefn() =
let z = 2
let z = z * 2
printfn "hi"
samplefn()
2nd version
#light
let samplefn() =
let z = 2
let z = z * 2
samplefn()
Only difference is the printfn is absent in the second version. I am using Visual Studio 2010 as my IDE. I am very new to F# but this error seems very strange to me. I guess I am missing some very important concept. Please explain.
Edit: Also if I do it outside the function I get error even with the first version of code.
#light
let z = 2
let z = z * 2
printfn "Error: Duplicate definition of value z"
let binds a value to a label but otherwise doesn't do much else. Your function contains two bindings but doesn't use them, and so you get an error.
To think of it another way, all functions in F# need a return value, which is the value of the last executed expression in your function. let doesn't have a return value so your function is invalid. To fix this you can add a return value, for example:
let samplefn() =
let z = 2
let z = z * 2
()
which defines a function that does absolutely nothing (returns unit). Perhaps a better example is this:
let samplefn() =
let z = 2
let z = z * 2
z
which will return 4 (the value of the binding for label z).
I think it is helpful to understand the non-light syntax here. Let's translate:
1st Version (let binding expressions)
let samplefn() =
let z = 2 in
let z = z * 2 in
printfn "hi";;
samplefn();;
The important thing to understand here is that all non-top-level let bindings are actually expressions of the form let <variable> = <expression1> in <expression2> where <variable> is bound to the result of <expression1> in a new scope <expression2>, and <expression2> is the return value of the entire expression. The light syntax makes you believe such let bindings are variable assignments / statements, when in fact it really is true that almost everything in F# is an expression.
Perhaps the following illustrates this more clearly:
let a = (let b = 3 in b + 2) //a is 5
2nd Version (top-level let bindings)
let z = 2;;
let z = z * 2;;
printfn "Error: Duplicate definition of value z";;
Top level let-bindings are terminated with ;;, indicating the completion of what may be thought of as a statement. The top-level is a single scope, and here we get an error for trying to bind z twice within the same scope. Whereas using the expression form of let bindings in Example 1, we bind z anew for each sub-scope in the expression chain. Note that we could do something like this at the top-level:
let z = (let z = 2 in z * 2);;
A let that is not at the top level (e.g. your indented ones) has to have a statement (actually an expression, as pst notes) called a "body" following the assignment. In the first example the body is printfn "hi", while the second example has no body. That's what the compiler is complaining about.
Note that in your function definitions the inner let expressions actually create nested scopes. That is, the let z = z * 2 actually creates a new value called z and binds to it the value of the outer z times 2, then uses it in the body of the let (which is the printfn in this case). A nested let will always have a body. It is the nesting which allows the seemingly duplicate definition.
Since an outermost let does not need a body, the compiler thinks you're trying to redefine z in the same scope, which is an error. You can use parentheses to tell the compiler how to properly interpret the last example:
let z = 2
(let z = z * 2
printfn "z = %d" z)
printfn "z = %d" z
The above will print z = 4
z = 2