In my last articles I gave an introduction in NaturalSpec, showed how to get started and demonstrated how we can use NaturalSpec to write automatically testable scenarios for C# projects. This time I will use the same “Car-Dealer”-sample to show how we can mock objects in NaturalSpec.
Mocking objects is an important technique in Test-driven development (TDD) and allows us to simulate complex behavior.
“If an object has any of the following characteristics, it may be useful to use a mock object in its place:
- supplies non-deterministic results (e.g. the current time or the current temperature);
- has states that are difficult to create or reproduce (e.g. a network error);
- is slow (e.g. a complete database, which would have to be initialized before the test);
- does not yet exist or may change behavior;
- would have to include information and methods exclusively for testing purposes (and not for its actual task).”
In our sample we want to mock the Dealer.SellCar() functionality. The first step is to create an C#-Interface for the Dealer:
namespace CarSellingLib { public interface IDealer { Car SellCar(int amount); } }
NaturalSpec is using Rhino.Mocks as the underlying mocking framework, so we have to create a reference to Rhino.Mocks.dll in our spec library.
Now we can modify our spec to:
// 1. open module module CarSpec
// 2. open NaturalSpec-Namespace open NaturalSpec // 3. open project namespace open CarSellingLib // define reusable values let DreamCar = new Car(CarType.BMW, 200) let LameCar = new Car(CarType.Fiat, 45) // 4. define a mock object and give it a name let Bert = mock<IDealer> "Bert" // 5. create a method in BDD-style let selling_a_car_for amount (dealer:IDealer) = printMethod amount dealer.SellCar amount // 6. create a scenario [<Scenario>] let When_selling_a_car_for_30000_it_should_equal_the_DreamCar_mocked() = As Bert |> Mock Bert.SellCar 30000 DreamCar // 7. register mocked call |> When selling_a_car_for 30000 |> It should equal DreamCar |> It shouldn't equal LameCar |> Verify
As you can see we changed part 4 (in order to get a mocked IDealer instead of the concrete Dealer). In part 7 we register our mocked behavior. We want that whenever Bert.SellCar is called with parameter 30000 the DreamCar should be returned.
The Verify-function checks if the mocked function has been called. If not the scenario will fail.
If we verify our spec with a NUnit runner we get the following output:
Tags: F#, Mocking, NaturalSpec, Rhino.MocksScenario: When selling a car for 30000 it should equal the DreamCar mocked
– As Bert
– With Mocking
– When selling a car for 30000
=> It should equal BMW (200 HP)
=> It should not equal Fiat (45 HP)
==> OK
Is there support in this framework for mocking of an object for which there is no interface, such as the standard SqlConnection in namespace System.Data.SqlClient?
Comment by Bjarte — Friday, 17. April 2009 um 14:26 Uhr