Stubs and Mocks in cfSpec 0.3

I noticed last week that there is a new version of cfSpec available and took the oportunity to download it.

I was very keen to try out the new Mocking feature as a new project I started needs to be able to do that because the web services it will be using won't be available until after the project has been underway for several weeks. 'Great,' I thought, I can start straight away and use Mocks for the missing web services.

Unfortunately there is no documentation yet, but Ron Hopper very kindly sent me a document that helped me get started with writing some simple Mocks and this week I should be able to nail down some more realistic ones for my project.

The new version of cfSpec builds upon the great work done in earlier versions with Stubs, so using a Mock is very similar but gives you extra abilities to set what the object returns and test how many times it is called. So let's start with some examples of stubs which worked in version 0.2.

In this first example I create a stub thet returns an expected value and check that it does what it should.

<cfimport taglib="/cfspec" prefix="">

<describe hint="As a tester I want to create a stubObject that myObject can call so that I can test myObject before the called object exists.">
   
   <beforeAll>
      <cfset myStub = stub()>
      <cfset myStub.stubs("Test").returns("The expected value")>
   </beforeAll>

   <it should="return the expected value">
      <cfset $(myStub.test()).shouldBe("The expected value")>
   </it>

</describe>

You get the idea? Normally of course I would be injecting the stub into a CFC I had written or calling it from some CFML code.

You can also tell a stub to return different valuse each time it gets called and in the next exmaple it will cycle arund the three values I have told it to return.

<cfimport taglib="/cfspec" prefix="">

<describe hint="As a tester I want to create a mockObject that myObject can call so that I can test myObject before the called object exists.">
   
   <beforeAll>
      <cfset myStub = stub()>
      <cfset myStub.stubs("Test").returns("The expected value")>
      <cfset myStub.stubs("Test").returns("Another value")>
      <cfset myStub.stubs("Test").returns("More than you expect")>
   </beforeAll>

   <it should="return the expected value">
      <cfset $(myStub.test()).shouldBe("The expected value")>
   </it>
   
   <it should="return the expected value">
      <cfset $(myStub.test()).shouldBe("Another value")>
   </it>
   
   <it should="return the expected value">
      <cfset $(myStub.test()).shouldBe("More than you expect")>
   </it>

</describe>

If your stub needs to return an error when called you can do that too with the .throws method:

<cfset myStub.stubs("test").throws("anException","With this message","And this detailed message")>

As a shortcut you can also write your returned values in a list:

<cfset myStub.stubs("aDifferentMethod").returns("A Value","Next value","Final Value")>

So what extra facilities are there in cfSpec 0.3 ?

The firts is the ability to check that your code is calling the mock the required number of times:

<cfset myMock.expects("myMethod").times(3).returns("myValue")>

You also have the ability to set up expectations as to what methods will be called and in what sequence. So as an example you can specify a sequence of calls and cfSpec will check that the calls are made to the mock object in the expected sequence.

<cfscript>
   coffee = sequence('morningCoffee');
   myMock.expects('grindBeans').with("beans").inSequence(morningCoffee);
   myMock.expects('pourWater').inSequence(morningCoffee);
   myMock.expects('startBrewing').inSequence(morningCoffee);
</cfscript>

I am still getting to grips with all the new things I can do with cfSpec 0.3 and will post some more when I have it.

Thanks again to Ron Hopper for his help and the excellent cfSpec.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.