Unit Testing with Foq

Preview:

Citation preview

Unit Testing with Foq@ptrelford on @c4fsharp March 2013

Go download on Nuget or foq.codeplex.com

Testing Language

A Language for Testing

what should a language for writing

acceptance tests be?

A Language for Testing

Tests operate by example

they describe specific

scenarios and responses

A Language for Testing

I wonder if a different kind of

programming language

is required.- Martin Fowler 2003

UNIT TESTING WITH F#F# as a Testing Language

NUnit

F# NUnitmodule MathTest =

open NUnit.Framework

let [<Test>] ``2 + 2 should equal 4``() = Assert.AreEqual(2 + 2, 4)

C# NUnitusing NUnit.Framework;

[TestFixture]public class MathTest{ [Test] public void TwoPlusTwoShouldEqualFour() { Assert.AreEqual(2 + 2, 4); }}

FsUnit

let [<Test>] ``2 + 2 should equal 4``() = 2 + 2 |> should equal 4

Unquote

let [<Test>] ``2 + 2 should equal 4``() = test <@ 2 + 2 = 4 @>

.NET MOCKINGF# as a Testing Language

Mocking libraries

unittesting

Moq

var mock = new Mock<ILoveThisFramework>();

// WOW! No record/replay weirdness?! :)mock.Setup(framework => framework.DownloadExists("2.0.0.0")) .Returns(true) .AtMostOnce();

// Hand mock.Object as a collaborator and exercise it, // like calling methods on it...ILoveThisFramework lovable = mock.Object;bool download = lovable.DownloadExists("2.0.0.0");

// Verify that the given method was indeed called with the expected valuemock.Verify(framework => framework.DownloadExists("2.0.0.0"));

FakeItEasy

// Creating a fake object is just dead easy!// No mocks, no stubs, everything's a fake!var lollipop = A.Fake<ICandy>();var shop = A.Fake<ICandyShop>();

// To set up a call to return a value is also simple:A.CallTo(() => shop.GetTopSellingCandy()).Returns(lollipop);

// Use your fake as you would an actual instance of the faked type.var developer = new SweetTooth();developer.BuyTastiestCandy(shop);

// Asserting uses the exact same syntax as when configuring calls,// no need to teach yourself another syntax.A.CallTo(() => shop.BuyCandy(lollipop)).MustHaveHappened();

F# Object Expressions

Mock objectMock<IShopDataAccess>() .Setup(fun data -> <@ data.GetProductPrice(any()) @>) .Calls<int>(function | 1234 -> 45M | 2345 -> 15M | productID -> failwith "Unexpected" ) .Create()

Object Expression{ new IShopDataAccess with member __.GetProductPrice(productId) = match productId with | 1234 -> 45M | 2345 -> 15M | _ -> failwith "Unexpected" member __.Save(_,_) = failwith "Not implemented"}

FOQ MOCKINGF# as a Testing Language

WTF

Foq: IList<char>

// Arrangelet xs = Mock<IList<char>>.With(fun xs -> <@ xs.Count --> 2 xs.Item(0) --> '0' xs.Item(1) --> '1' xs.Contains(any()) --> true xs.RemoveAt(2) ==> System.ArgumentOutOfRangeException() @> )// AssertAssert.AreEqual(2, xs.Count)Assert.AreEqual('0', xs.Item(0))Assert.AreEqual('1', xs.Item(1))Assert.IsTrue(xs.Contains('0'))Assert.Throws<System.ArgumentOutOfRangeException>(fun () -> xs.RemoveAt(2))

Foq: Anonymous Type

var order = new Mock<IOrder>() .SetupProperties(new { Price = 99.99M, Quantity = 10, Side = Side.Bid, TimeInForce = TimeInForce.GoodTillCancel }) .Create();Assert.AreEqual(99.99M, order.Price);Assert.AreEqual(10, order.Quantity);Assert.AreEqual(Side.Bid, order.Side);Assert.AreEqual(TimeInForce.GoodTillCancel, order.TimeInForce);

Foq: Type Inference

let [<Test>] ``order sends mail if unfilled`` () = // setup data let order = Order("TALISKER", 51) let mailer = mock() order.SetMailer(mailer) // exercise order.Fill(mock()) // verify verify <@ mailer.Send(any()) @> once

Foq Sequences

let [<Test>] ``verify sequence of calls`` () = // Arrange let xs = Mock.Of<IList<int>>() // Act xs.Clear() xs.Add(1) // Assert Mock.VerifySequence <@ xs.Clear() xs.Add(any()) @>

FOQ DEPLOYMENTF# as a Testing language

Deployment

Nuget DowloadCodePlex Download

FOQ APIF# as a testing language

LINQ or Quotations

Setup a mock method in C# with a lambda expression:

new Mock<IList<int>>()

.Setup(x => x.Contains(It.IsAny<int>())).Returns(true)

.Create();

Setup a mock method in F# with a Code Quotation:

Mock<System.Collections.IList>()

.Setup(fun x -> <@ x.Contains(any()) @>).Returns(true)

.Create()

Fluent Interface orFunctions

FOQ IMPLEMENTATIONF# as a testing language

LOC: Moq vs FakeItEasy

Moq

Total 16454

{ or } 2481

Blank 1933

Null checks 163

Comments 7426

Useful lines 4451

FakeItEasy

Total 11550

{ or } 2948

Blank 1522

Null checks 92

Comments 2566

Useful lines 4422

Fock (aka Foq)

Fock v0.1

127 Lines• Interfaces• Methods• Properties

Fock v0.2

200 Lines• Interfaces• Abstract Classes• Methods• Properties• Raise Exceptions

LOC: Foq 0.8.1

Foq.fs

Total 666

Foq.fs + Foq.Linq.fs

Total 933

QUESTIONSF# as a Testing Language

What The Foq?

Recommended