Multiple items
type CosTam =
new : unit -> CosTam
member ( here I want to test if page works correctly ) : unit -> 'a
Full name: index.CosTam
--------------------
new : unit -> CosTam
val sprintf : format:Printf.StringFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
type Generators =
static member muiKastomowyGeneratorek : obj
Full name: index.Generators
static member Generators.muiKastomowyGeneratorek : obj
Full name: index.Generators.muiKastomowyGeneratorek
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = System.Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
val ignore : value:'T -> unit
Full name: Microsoft.FSharp.Core.Operators.ignore
property Generators.muiKastomowyGeneratorek: obj
val config : obj
Full name: index.config
What is FsCheck?
What's the problem?
- How to test functions which arguments admit a wide range of values
- How to test functions which arguments needs to fulfill some restriction
How we solve the problem right now?
- TestSuite in nUnit for various function inputs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
|
using System;
using NUnit.Framework;
[TestFixture]
class TestSomething
{
[TestCase(1, "ene")]
[TestCase(2, "dułe")]
[TestCase(3, "rabe")]
[TestCase(4, "bocian")]
[TestCase(5, "złapał")]
[TestCase(6, "żabę")]
public void TestCos(int paramFirst, string ParamSecond)
{
//do magic
Assert.AreEqual(result, expectedResult);
}
}
|
How we solve the problem right now?
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
|
using developwithpassion.specifications.rhinomocks;
using Machine.Specifications;
public class TestSomething : Observes
{
Establish that = () => //set something
class When_something_return_this1
{
Because of = () => result = sut.DoSomething(1, "ene");
It should_return_this = result.ShouldEquals(expectedResult);
}
class When_something_return_this2
{
Because of = () => result = sut.DoSomething(2, "dułe");
It should_return_this = result.ShouldEquals(expectedResult);
}
//...
}
|
How we solve the problem right now?
- Multiple specs (behaviours)
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
|
using developwithpassion.specifications.rhinomocks;
using Machine.Specifications;
public class TestSomething : Observes
{
private Establish that = () => //set something
[Behaviors]
class ProperTest
{
result.ShouldEquals(expectedResult);
}
class When_something_return_this1
{
Because of = () => result = sut.DoSomething(1, "ene");
Behaves_like<ProperTest> a_proper_test;
}
//...
}
|
How to start with FsCheck?
What we should install to start writting tests with FsCheck?
How syntax looks like?
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
|
open FsCheck
open NUnit.Framework
[<TestFixture>]
type CosTam() =
[<Test>]
member this.``here I want to test if page works correctly``() =
use client = HttpClient()
(
let test(page: PageTest) =
let url =
sprintf "%s/v1/Page?userId=%s&name=%s" endpointAddress userId page.name
let response = client.GetAsync url
let result = response.Result.StatusCode
let label =
sprintf "Page %s returns %s instead of 200" page.name (result.ToString())
(result = HttpStatusCode.OK)
.Label(label)
Check.QuickThrowOnFailure test
)
|
How the pipeline of writing FsCheck test looks like?
- tag class with TestFixture attribute
- tag tests method with Test attribute
- test method must be public, if it's not, then nunit will throw an exception method is not public
- inside test define function with input parameters which should changed in every test execution
- run test as Check.Quick(config) nameOfLocalFunction or Check.QuickThrowOnFailure nameOfLocalFunction
- by default per every test, it is run with different input values 100 times
Shrinker
- What he does?
- If for some input a test fails, the input is being shrunk
- It shinks input till it doesn't causes failure
Shrinker example (before shrinking)
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
|
<topic>
<title>My first publication</title>
<body>
<image href="unicorn.pdf">
<p>Hello <b>world!</b></p>
<table>
<title>table</title>
<tbody>
<row>
<entry>aaa</entry>
</row>
</tbody>
</table>
</body>
</topic>
|
Shrinker example (after shrinking)
1:
2:
3:
4:
5:
6:
|
<topic>
<title/>
<body>
<p><b>w</b></p>
</body>
</topic>
|
Generators
- generators for simple datatypes are available by default
- it is possible to create own generators for more complicated types
- own generators could be register globally or per test
Custom generator
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
|
type Generators =
static member muiKastomowyGeneratorek =
Arb.generate<float>
|> Gen.suchThat ((<) 0.)
|> Arb.fromGen
Arb.register<Generators>() |> ignore
//using per tests
Check.Quick (forAll Generators.muiKastomowyGeneratorek test)
|
Custom configuration
- by default test runs 100 times
- granularity of generated data could be also changed
1:
2:
3:
4:
5:
6:
7:
8:
|
let config = {
Config.Quick with
MaxTest = 1000 //number of tests to run
StartSize = 100 //default value is 1
EndSize = 100 //default value is 100
}
Check.One(config, test)
|
Let's write a simple test
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
|
open FsCheck
open NUnit.Framework
[<TestFixture>]
type CosTam() =
[<Test>]
member this.``here I want to test if page works correctly``() =
use client = HttpClient()
(
let test(page: PageTest) =
let url =
sprintf "%s/v1/Page?userId=%s&name=%s" endpointAddress userId page.name
let response = client.GetAsync url
let result = response.Result.StatusCode
let label =
sprintf "Page %s returns %s instead of 200" page.name (result.ToString())
(result = HttpStatusCode.OK)
.Label(label)
Check.QuickThrowOnFailure test
)
|