Specflow When/Then with Rhino Mocks

376 views
Skip to first unread message

Geo

unread,
Oct 26, 2010, 6:50:13 PM10/26/10
to SpecFlow
Greetings guys,
If possible I'd like suggestions on how to best setup mocking so that
it blends well with the expressiveness allowed by Specflow...

Say I have the following scenario:

Scenario: The file has valid number of lineas
Given that there are 3000 records on the database
And that the file valid_file.txt has 3000 lines
When the file is parsed
Then the file must be flagged as valid
And the formatter process must be called

For such scenario I have this code:

[Given(@"that there are (\d{1,5}) records on the database")]
public void that_there_are_x_records_on_the_database(int
Count)
{
if (Mocks == null) Mocks = new MockRepository();

var segmentRepo = Mocks.StrictMock<ISegmentRepository>();

Expect.Call(segmentRepo.Get_segments_count()).Return(Count);

ScenarioContext.Current.Add("segmentRepo", segmentRepo);
}

[Given(@"that the file has (\d{1,5}) lines")]
public void And_that_file_x_has_x_lines(string Filename, int
Lines)
{
var lines = "";
for (var i = 0; i < Lines; i++)
lines += "01-01-01-001-001,10/23/2010 10:03 AM,
30,80,60\n";

var ioWrapper = Mocks.StrictMock<ISystemIOWrapper>();

Expect.Call(ioWrapper.File_contents(Filename)).IgnoreArguments().Return(lines.Substring(0,
lines.Length-2).Split('\n'));

ScenarioContext.Current.Add("ioWrapper", ioWrapper);
}

[When(@"the file is parsed")]
public void When_the_file_is_parsed()
{
var segmentRepo =
(ISegmentRepository)ScenarioContext.Current["segmentRepo"];
var ioWrapper =
(ISystemIOWrapper)ScenarioContext.Current["ioWrapper"];

var parser = new NewFileParser();
parser.IO_wrapper = ioWrapper;
parser.Segment_repository = segmentRepo;

Mocks.ReplayAll();
parser.Parse("filePath");

ScenarioContext.Current.Add("parser", parser);
}

[Then(@"the file must be flagged as valid")]
public void Then_the_file_must_be_flagged_as_valid()
{
// I do nothing here, but I think I should
}

[Then(@"the formatter process must be called")]
public void Then_the_formatter_process_must_be_called()
{
var parser = (NewFileParser)
ScenarioContext.Current["parser"];

Mocks.VerifyAll();
Assert.IsTrue(parser.Is_valid);
}

Now, while it produces a decent result (I think), It feels a bit like
code-smell due to the fact that I'm not asserting where I should...
but I have not found any other way to do it, even when using the AAA
syntax in rhino it tells me that I cannot do it because it's in record
mode or something like that.

Any help/suggestions/hints/rants are greatly appreciate it.

Thanks a lot guys.
Geo

PS: Sorry for the long post

Gáspár Nagy

unread,
Oct 27, 2010, 7:53:34 AM10/27/10
to SpecFlow
Hi,

RhinoMocks supports AAA, but unfortunately rather in an Arrange-Assert-
Act way, that is not so easy to fit. If you don't have a strong
argument for Rhino, you can switch to Moq.

I had a post to Kevin's question about the mocking... Besides those
comments, I think it makes sense to cleanly separate between using
mocks and stubs in your tests. In functional testing, especially if
you isolate the database, you need to use stubs not mocks (so
basically you need to specify a stub database with some initial data
and finally verify, that the stub database contains the expected
result data). The same can stand for other things than the database,
like the file system. For stubs, you don't need to verify if this or
that action was called, so there is no need to call VerifyAll, also no
need to create strict mocks. I would automate your scenario in the
following way:

Scenario: The file has valid number of lineas
Given that there are 3000 records on the database -> create
a stub repo with 3000 record (same as you did)
And that the file valid_file.txt has 3000 lines -> create a
stub file with 3000 lines (same as you did)
When the file is parsed -> create parser, call parse (same as
you did, except replayall)
Then the file must be flagged as valid -> Assertion
(Assert.IsTrue(...)) on stub file or on the stub database, whether the
flas is true (i don't know fully what flagging means)
And the formatter process must be called -> Assertion on the
parser (like what you have in the last line)

PS: other comment: for communicating between steps in the same class,
i think it is more convenient to use member fields or a special
context class injected into your class than using the ScenarioContext.

Geo

unread,
Oct 27, 2010, 12:15:33 PM10/27/10
to SpecFlow
Thanks for the reply Gáspár, I'll certainly try Moq as I don't a
specific requirement to use it.
Thanks for pointing out the usage of stubs, I'm usually a bit lost as
to when use one or the other, but I believe I'll get there someday.
I'll also try the context class and see if it's more expressive.

Thanks and fantastic job with specflow BTW.

Kevin Krac

unread,
Oct 27, 2010, 4:21:12 PM10/27/10
to spec...@googlegroups.com
Regarding Rhino Mock specifically, as Gaspar said, it supports AAA.

1) in the Given, you create the mock (the "A"rrange)
2) in the Then, you execute the action (the "A"ct) on the object under test
3) you verify your mocked object was called (the "A"ssert)
something like:

ioWrapper.AssertWasCalled(w => w.File_Contents(FileName))

It is more clear and easier to write. You no longer have to pass from Record state to Replay explicitly.

Geo

unread,
Oct 28, 2010, 12:48:19 AM10/28/10
to SpecFlow
Kevin,
I tried doing it like that but I kept on getting errors about record/
replay states, and unfortunately could not pinpoint where the error
was; I'm trying Moq now but will come back to Rhino and try it again
for completeness purposes.

Thanks

Steven Zhang

unread,
Oct 31, 2010, 12:24:52 AM10/31/10
to spec...@googlegroups.com
Hi,

It's neither a SpecFlow issue, nor a RhinoMocks issue. It is a improper using issue.

Since RhinoMocks 3.5, the StrickMock is not recommended. The "Arrange-Act-Assert" mode is the first choice.

The major feature in Rhino Mocks 3.5 is the AAA syntax. Arrange, Act, Assert is a classic way to set up your tests. First you arrange the state, then you execute the code under test, finally you assert that the expected state change happened. With interaction based testing, this was generally impossible, and required that you would use the Record/Replay model. This was a common case for confusion for people new to interaction based testing. The AAA syntax solve this problem.

BTW, by using "GenerateMock" of RhinoMocks, I made some change on your sample code. Here it is.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using Rhino.Mocks;
using Domain;
using NUnit.Framework;

namespace SpecFlowGroup1 {
[Binding]
    public class StepDefinition1 {

[Given(@"that there are (\d+) records on the database")]
       public void that_there_are_x_records_on_the_database(int Count)
       {
           var segmentRepo = MockRepository.GenerateMock<ISegmentRepository>();
           segmentRepo.Expect(x => x.Get_segments_count()).Return(Count);

           ScenarioContext.Current.Add("segmentRepo", segmentRepo);
       }

[Given(@"that the file (\w+\.\w+) has (\d+) lines")]
       public void And_that_file_x_has_x_lines(string Filename, int Lines)
       {
           var lines = "";
           for (var i = 0; i < Lines; i++)
               lines += "01-01-01-001-001,10/23/2010 10:03 AM,30,80,60\n";

           var ioWrapper = MockRepository.GenerateMock<ISystemIOWrapper>();
           
           ioWrapper.Expect(x => x.File_contents(Filename)).IgnoreArguments().Return(lines.Substring(0, lines.Length - 2).Split('\n'));
           
           ScenarioContext.Current.Add("ioWrapper", ioWrapper);
       }

[When(@"the file is parsed")]
       public void When_the_file_is_parsed()
       {
           var segmentRepo = (ISegmentRepository)ScenarioContext.Current["segmentRepo"];
           var ioWrapper = (ISystemIOWrapper)ScenarioContext.Current["ioWrapper"];

           var parser = new NewFileParser();
           parser.IO_wrapper = ioWrapper;
           parser.Segment_repository = segmentRepo;

           parser.Parse("filePath");

           ScenarioContext.Current.Add("parser", parser);
       }

[Then(@"the file must be flagged as valid")]
       public void Then_the_file_must_be_flagged_as_valid()
       {
          // I do nothing here, but I think I should
       }

[Then(@"the formatter process must be called")]
       public void Then_the_formatter_process_must_be_called()
       {
           var parser = (NewFileParser)ScenarioContext.Current["parser"];

           var segmentRepo = (ISegmentRepository)ScenarioContext.Current["segmentRepo"];
           var ioWrapper = (ISystemIOWrapper)ScenarioContext.Current["ioWrapper"];

           segmentRepo.VerifyAllExpectations();
           ioWrapper.VerifyAllExpectations();
           
           Assert.IsTrue(parser.Is_valid);
       }
    }
}
 
See http://gist.github.com/656107 for the whole file.
--
Regards,
Steven Zhang

Geo

unread,
Nov 1, 2010, 12:43:21 AM11/1/10
to SpecFlow
Thanks to all for your replies and suggestions, I now realize I was
using it wrong and can report It's working correctly using the AAA
mode as suggested by a few of you!
thanks again

On Oct 31, 12:24 am, Steven Zhang <jdomzh...@gmail.com> wrote:
> Hi,
>
> It's neither a SpecFlow issue, nor a RhinoMocks issue. It is a improper
> using issue.
>
> Since RhinoMocks 3.5, the StrickMock is not recommended. The
> "Arrange-Act-Assert" mode is the first choice.
>
> From Ayende's website,http://www.ayende.com/wiki/Rhino+Mocks+3.5.ashx
>
> > *The* major feature in Rhino Mocks 3.5 is the AAA syntax. Arrange, Act,
> Seehttp://gist.github.com/656107for the whole file.
> > > > > >             var parser =...
>
> read more »
Reply all
Reply to author
Forward
0 new messages