It appears that my property test that's running as a unit test fails even though it really passes.
The code is as follows:
module Tests.Units
open FsUnit
open NUnit.Framework
open NUnit.Core.Extensibility
open FsCheck.NUnit
open FsCheck.NUnit.Addin
open FsCheck
let add x y = (x + y)
let commutativeProperty x y =
let result1 = add x y
let result2 = add y x // reversed params
result1 = result2
[<Test>]
let ``When I add two numbers, the result should not depend on parameter order``()=
Check.Quick commutativeProperty |> should equal true
Summary:
Test Name: When I add two numbers, the result should not depend on
parameter order
Test FullName: Tests.Units.When I add two numbers, the result should
not depend on parameter order
Test Outcome: Failed
Result StackTrace: at
FsUnit.TopLevelOperators.should[a,a](FSharpFunc`2 f, a x, Object y) in
d:\GitHub\FsUnit\src\FsUnit.NUnit\FsUnit.fs:line 44
at Tests.Units.When I add two numbers, the result should not depend on
parameter order()
Result Message: Expected: true, but was
Result StandardOutput: Ok, passed 100 tests.
Am I reading this right?
What am I missing?
Use Check.QuickThrowOnFailure instead:
[<Test>]
let ``When I add two numbers, the result should not depend on parameter order``()=
Check.QuickThrowOnFailure commutativeProperty
Since it looks like you're attempting to run properties from within a unit testing framework like NUnit, you should consider to instead use one of the Glue Libraries for FsCheck:
FsCheck.Nunit
FsCheck.Xunit
This would enable you to write properties using the [<Property>] attribute:
[<Property>]
let ``When I add two numbers, the result should not depend on parameter order``x y =
let result1 = add x y
let result2 = add y x // reversed params
result1 = result2
Due to the poor extensibility API for NUnit, you can save yourself a lot of grief using xUnit.net instead of NUnit.
Related
Let's say I wanted to have an alias of sprintf, I would simply do this:
namespace FSharp
module Core =
let specialsprintf x y =
sprintf x y
This would bring me the same compilation-time advantages (compared to its C# cousin API System.String.Format) of sprintf such as type-checking, checking number of parameters passed is correct, etc.
However, let's say I wanted to disable this compilation-time niceties and write a simple version of sprintf by calling String.Format underneath. Could this be possible? I know the goal sounds stupid but I want to do this mental exercise to make sure I understand how F# typing works here. If I do this (supposing we only can pass one parameter):
namespace FSharp
module Core =
let specialsprintf x y =
#if NORMAL_FSHARP
sprintf x y
#else
let x = x.Replace("%s", "{0}")
System.String.Format(x,y)
#endif
It doesn't even compile, the error is:
~/FSharpPlayground.fs(17,17): Error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. (FS0072) (FSharpPlayground)
Mmmm why?
Ok, if I specify the type like this:
namespace FSharp
module Core =
let specialsprintf
#if NORMAL_FSHARP
x
#else
(x: string)
#endif
y =
#if NORMAL_FSHARP
sprintf x y
#else
let x = x.Replace("%s", "{0}")
System.String.Format(x,y)
#endif
Then I end up with a compilation error in the caller:
~/FSharpPlaygroundUse.fs(48,48): Error FS0001: This expression was expected to have type 'obj []' but here has type 'string' (FS0001)
I guess I need now to qualify the type of y now, but not sure how to do it in case I wanted to extend it to be able to use 2 arguments instead of just 1 (I don't manage to make it work with the ParamArray attribute). Something tells me that I probably also need an uncurry function but I'm a bit lost :-/
I'm assuming that what you want is something like sprintf but variadic, and without type checking the format.
There's no 'uncurrying' or variable argument functions for F#, unfortunately.
That being said, there's the option of using a parameter array. ParamArray is only valid on class members not bindings, so we can settle for a static member which is similar in scope to a let fn () =.
type SpecialPrint =
static member sprintf (format, [<ParamArray>] args) =
let index = ref -1
let stringFormat = Regex.Replace(format, "%[a-z]", (fun _ -> sprintf "{%d}" (Interlocked.Increment index)))
String.Format(stringFormat, args)
With;
let result = SpecialPrint.sprintf ("Hello %s%s", "World", "!") //Hello World!
Let's say I have a value defined as a sort of commission formula
let address_commission = 1.0 // minimal simplified example
and I want to apply the above said commission to an amount I'm reading from the DB (the code is from a window WCF service I have in production)
let address_commission = 1.0 // minimal simplified example
new Model.ClaimModel(
//RequestRow = i, recounting
Code = (row.["claim_code"] :?> string),
EvtDate = (row.["event_date"] :?> DateTime),
// skipping lines...
Amount = (row.["amount"] :?> double) * address_commission,
now I see that the amount line compiles fine, but I also need to include the same commission in the following
PrevAmount = (if row.IsNull("prev_amount") then Nullable() else (row.["prev_amount"] :?> Nullable<double>)),
which is wrong since The type 'float' does not match the type 'obj'
Therefore I've tried also
PrevAmount = (if row.IsNull("prev_amount") then Nullable() else (((row.["prev_amount"] :?> double) * address_commission) :?> Nullable<double>)),
but it also fails with The type 'double' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.
What is the correct way to handle this?
:?> is a dynamic cast and it's only checked at run-time so better try to avoid it. If you are accessing databases it helps to open the open FSharp.Linq.NullableOperators namespace. (The link is gone for me but it's somewhere on docs or msdn). Then you can use ?*? and similar operators. For example:
let x = System.Nullable<float> 4.
let y = x ?* 3.0
//val y : System.Nullable<float> = 12.0
You can have ? on either or both sides.
You will get back a Nullable float which you can coerce to an option with
Option.ofNullable(y) or to a double float y.
I'm going to use only one type coercion and wrap it within a Nullable(...)
PrevAmount = (if row.IsNull("prev_amount") then Nullable() else Nullable((row.["prev_amount"] :?> double) * address_commission)),
It compiles and looks ok to me, but I'm still open to different answers if they are more correct than mine
I've got a type Average with a field count that's a positive int64 and a double field called sum.
I made an arbitrary that generates valid instances with
let AverageGen = Gen.map2 (fun s c -> Average(float(s),int64(int(c))) (Arb.Default.NormalFloat().Generator) (Arb.Default.PositiveInt().Generator) |> Arb.fromGen
How do I get this to be generate arguments with type Average in Property style tests in xUnit?
[<Property>]
static member average_test(av:Average) = ...
type Generators =
static member TestCase() =
{ new Arbitrary<TestCase>() with
override x.Generator =
gen { ...
return TestCase(...) }}
[<Property(Arbitrary=[|typeof<Generators>|])>]
I think Vasily Kirichenko's solution is the correct one, but just for completeness sake, I've also been able to make it work with this imperative function invocation style:
do Arb.register<Generators>() |> ignore
...if you assume a Generators class as in Vasily Kirichenko's answer.
Edit, much later...
While the above, imperative approach may work, I never use it because of its impure nature. Instead, I sometimes use the Arbitrary directly from within the test. With the AverageGen value above (which I'll rename to averageGen, because values should be camelCased), it could look like this:
[<Property>]
let member average_test () =
Prop.forAll averageGen (fun avg ->
// The rest of the test goes here... )
In reading John Palmer's answer to What is the difference between mutable values and immutable value redefinition?, John notes that
This sort of redefinition will only work in fsi.
In working with F# Interactive (fsi) I guess I subconsciously knew it, but never paid attention to it.
Now that it is apparent, why the difference?
More specifically please explain how the internals are different between fsi and the compiler such that this occurs by design or result of differences?
If the answer can elaborate on the internal structures that hold the bindings that would be appreciated.
The semantics are consistent with the way FSI compiles interactive submissions to an FSI session: each interactive submission is compiled as module which is open to subsequent interactive submissions.
The following is close to what FSI actual does and illustrates how let binding shadowing works across interactive submissions:
FSI Submission #1: let x = 1;;
module FSI_1 =
let x = 1
open FSI_1 //FSI_1.x is now bound to 1 and available at the top level
FSI Submission #2: let x = 2;;
module FSI_2 =
let x = 2
open FSI_2 //FSI_1.x is now shadowed by FSI_2.x which is bound to 2 and available at the top level
You can see the actual details how how the dynamic FSI assembly is compiled by using reflection on the FSI_ASSEMBLY assembly within the FSI app domain. Each interactive submission is literally emitted as a module (.NET class) with the naming pattern FSI_####. FsEye uses these facts to discover the state of FSI top-level bindings: https://code.google.com/p/fseye/source/browse/tags/2.0.1/FsEye/Fsi/SessionQueries.fs#24
The key takeaway in regard to #JohnPalmer's answer is that top-level FSI definitions cannot be mutated, when they are "redefined" they are merely being shadowed. We can show this as follows:
> let x = 1;; //our original definition of x
val x : int = 1
> let f () = x;; //capture x
val f : unit -> int
> let x = 2;; //shadow our original definition of x
val x : int = 2
> f();; //returns the original x value, which is still 1 rather than 2
val it : int = 1
I am trying to figure out to modify quotations and then evaluate them. Here I am starting basic and just trying to create a quotation using the Quotations api. The quotation binds OK, but I get an error when evaluating.
#r #"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.dll"
#r #"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
open Microsoft.FSharp.Linq
let hardway =
Expr.Let(
new Var("x", typeof<int>),
Expr.Value(10),
Expr.GlobalVar("x").Raw)
hardway.EvalUntyped()
Binding session to 'FSharp.PowerPack.Linq.dll'...
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at Microsoft.FSharp.Collections.MapTreeModule.find[TValue,a](IComparer`1 comparer, TValue k, MapTree`2 m)
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 459
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 704
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 677
at Microsoft.FSharp.Linq.QuotationEvaluation.CompileImpl[a](a e, Boolean eraseEquality) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 837
at Microsoft.FSharp.Linq.QuotationEvaluation.Expr.EvalUntyped(FSharpExpr ) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 854
at <StartupCode$FSI_0009>.$FSI_0009.main#()
Stopped due to error
To get this working using global variables, you'd need to write it like this:
let hardway =
Expr.Let(
Var.Global("x", typeof<int>),
Expr.Value(10),
(Expr.GlobalVar<int>("x")) )
hardway.EvalUntyped()
Var.Global and Expr.Global use some shared global dictionary of variables that the F# quotations library uses to make it possible to get the same variable instance without explicitly passing Var values around (as in Stringer's solution).
However, I think that creating Var value only once and then keeping a reference to the object (and ussing the same object in the expression) leads to more readable code, so I'd prefer Stringer's solution.
A few points about my code:
You need to use Var.Global instead of new Var because the second option doesn't store the variable in the global dictionary.
You need to specify the type explicitly in Expr.GlobalVar - if you don't do that, F# will use obj and that's a different variable (they are indexed by name and type).
I don't know how to use GlobalVar so I let others answer on this. Here's a workaround in waiting for a better solution:
let hardway =
let v = new Var("x", typeof<int>)
Expr.Let(
v,
Expr.Value(10),
Expr.Var(v))
let res = hardway.EvalUntyped() // res is 10
Unquote has a custom reflection-based evaluation engine which allows you to evaluate synthetic quotations by passing in a variable environment rather than needing to make the variable binding part of the expression itself. So you could do the following:
open Swensen.Unquote
open Microsoft.FSharp.Quotations
let unquoteway = Expr.Var(Var("x", typeof<int>))
let environment = Map.ofList [("x", box 10)]
unquoteway.Eval(environment)
This is interesting because the environment you pass in is the very environment used for all variable bindings and resolutions throughout the expression evaluation so variable scoping rules are honored:
let unquoteway =
Expr.NewTuple(
[Expr.Var(new Var("x", typeof<int>))
Expr.Let(new Var("x", typeof<string>), Expr.Value("hello"), Expr.Var(new Var("x", typeof<string>)))])
let environment = Map.ofList [("x", box 10)]
unquoteway.Eval(environment)
//FSI output:
val unquoteway : Expr = NewTuple (x, Let (x, Value ("hello"), x))
val environment : Map<string,obj> = map [("x", 10)]
val it : obj = (10, "hello")