Mocking / collection property constraint

18 views
Skip to first unread message

Goatified Creature

unread,
Nov 16, 2009, 9:52:40 AM11/16/09
to Rhino.Mocks
Hi, I have been trying to write a unit test in C# for a Manager
method. I am mocking two DAOS. However, the parameter passed to the
manager method will be further populated by the manager and passed as
an argument to one DAO. I wish to place a constraint on the DAO call
to ensure this property was populated correctly. Maybe this is easier
to demonstrate through code....

// the manager to test
SearchManager managerToTest = new SearchManager();

// mock the two DAOs
MockRepository mocks = new MockRepository();
ISearchDAO mockedSearchDAO = mocks.StrictMock<ISearchDAO>
();
IServiceAreaDAO mockedServiceAreaDAO =
mocks.StrictMock<IServiceAreaDAO>();

// create a search criteria object that does not have it's
ServiceAreas collection populated
ArticleSearchCriteria criteria = new ArticleSearchCriteria
();


// now the manager method will populate the ServiceAreas
property of criteria with a collection of
// matching ServiceArea objects matching the below int
array
int[] serviceAreaIds = { 345435 };
ServiceArea serviceArea = new ServiceArea();

// and these will be the pretend results
ArticleSearchResult resultFromDAO = new ArticleSearchResult
();


using (mocks.Record())
{
Expect.Call(mockedServiceAreaDAO.GetById
(345435)).Return(serviceArea);


// Now, here, I want a contraint to say
// ensure criteria.ServiceAreas contains the above
serviceArea object. This will be
// set before calling the below DAO method.
Expect.Call(mockedSearchDAO.SearchForArticles
(criteria)).Return(resultFromDAO);

}
using (mocks.Playback())
{
// inject DAO dependencies
managerToTest.SearchDAO = mockedSearchDAO;
managerToTest.ServiceAreaDAO = mockedServiceAreaDAO;

// call the method ensuring correct results. This
works fine
Assert.That(managerToTest.SearchForArticles(criteria,
serviceAreaIds), Is.SameAs(resultFromDAO));


// Now, I shouldn't be validating the ServiceAreas
collection was populated through the assert methodology
Assert.That(criteria.ServiceAreas, Has.Member
(serviceArea));
}


I have been tearing my receding hair out all afternoon through the
Rhino Mocks documentation to understand how to test this scenario.

Cheers!!!

Goatified Creature

unread,
Nov 17, 2009, 8:11:26 AM11/17/09
to Rhino.Mocks
Hi Guys,

Sorry to bump, I just wondered whether I had commited a terrible sin,
or maybe my question is a little dumb!!

Cheers!

On Nov 16, 2:52 pm, Goatified Creature <p...@paulswilliams.me.uk>
wrote:

Alex McMahon

unread,
Nov 17, 2009, 8:19:11 AM11/17/09
to rhino...@googlegroups.com
My response:
  1. I don't see what's wrong with testing it the way you are at the moment.
  2. If you really don't like it then I'd take a look at http://www.ayende.com/wiki/Rhino+Mocks+3.5.ashx#ArgumentConstraints
  3. Also is there any reason you are using StrictMocks? it's almost always a 'bad idea'
  4. Any reason why you're using the old record/replay syntax? I'd always recommend using the AAA syntax (Arrange Act Assert)

2009/11/17 Goatified Creature <pa...@paulswilliams.me.uk>

Tim Barcz

unread,
Nov 17, 2009, 2:06:23 PM11/17/09
to rhino...@googlegroups.com
Where are people new to Rhino learning about record/replay?

I'd like to find/fix.

Tim

On 11/17/09, Alex McMahon <flux...@gmail.com> wrote:
> My response:
>
> 1. I don't see what's wrong with testing it the way you are at the
> moment.
> 2. If you really don't like it then I'd take a look at
> http://www.ayende.com/wiki/Rhino+Mocks+3.5.ashx#ArgumentConstraints
> 3. Also is there any reason you are using StrictMocks? it's almost always
> a 'bad idea'
> 4. Any reason why you're using the old record/replay syntax? I'd always
--
Sent from my mobile device

Tim Barcz
Microsoft C# MVP
Microsoft ASPInsider
http://timbarcz.devlicio.us
http://www.twitter.com/timbarcz

Alex McMahon

unread,
Nov 17, 2009, 3:14:29 PM11/17/09
to rhino...@googlegroups.com
I've been thinking the same. I think it's because the documentation about AAA syntax is a bit hidden http://www.ayende.com/wiki/Rhino+Mocks+3.5.ashx. And when you google for "rhino mocks documentation" you end up here:

http://www.ayende.com/wiki/Rhino+Mocks+Documentation.ashx

which is all old syntax, and what's more it has a simple example that uses StrictMock!! oh dear.

In fact it's pretty difficult to get to the AAA documentation from there. The easiest fix is probably to add a link the AAA syntax to this documentation page. And to say that this is the highly recommended approach. The slightly better change is probably to rearrange the documentation so that the 3.5 changes are incorporated and then to order the sections so AAA is the obvious answer, and also to mark all old syntaxes as not recommended.

2009/11/17 Tim Barcz <timb...@gmail.com>

Goatified Creature

unread,
Nov 17, 2009, 3:39:59 PM11/17/09
to Rhino.Mocks
Alex,

You are entirely correct. The record / replay syntax is the only
syntax I have picked up through top links from google since looking
at mocking for the last couple of months. It's only this week when
looking at contraints have I found the new syntax which looks a little
scary, especially when I have only 3 days left to complete my current
project.



On Nov 17, 8:14 pm, Alex McMahon <fluxmu...@gmail.com> wrote:
> I've been thinking the same. I think it's because the documentation about
> AAA syntax is a bit hiddenhttp://www.ayende.com/wiki/Rhino+Mocks+3.5.ashx.
> And when you google for "rhino mocks documentation" you end up here:
>
> http://www.ayende.com/wiki/Rhino+Mocks+Documentation.ashx
>
> which is all old syntax, and what's more it has a simple example that uses
> StrictMock!! oh dear.
>
> In fact it's pretty difficult to get to the AAA documentation from there.
> The easiest fix is probably to add a link the AAA syntax to this
> documentation page. And to say that this is the highly recommended approach.
> The slightly better change is probably to rearrange the documentation so
> that the 3.5 changes are incorporated and then to order the sections so AAA
> is the obvious answer, and also to mark all old syntaxes as not recommended.
>
> 2009/11/17 Tim Barcz <timba...@gmail.com>
>
>
>
>
>
> > Where are people new to Rhino learning about record/replay?
>
> > I'd like to find/fix.
>
> > Tim
>
> > On 11/17/09, Alex McMahon <fluxmu...@gmail.com> wrote:
> > > My response:
>
> > >    1. I don't see what's wrong with testing it the way you are at the
> > >    moment.
> > >    2. If you really don't like it then I'd take a look at
> > >    http://www.ayende.com/wiki/Rhino+Mocks+3.5.ashx#ArgumentConstraints
> > >    3. Also is there any reason you are using StrictMocks? it's almost
> > always
> > >    a 'bad idea'
> > >    4. Any reason why you're using the old record/replay syntax? I'd
> > always
> > >    recommend using the AAA syntax (Arrange Act Assert)
>
> > > 2009/11/17 Goatified Creature <p...@paulswilliams.me.uk>

Stephen Price

unread,
Nov 17, 2009, 8:52:06 PM11/17/09
to rhino...@googlegroups.com
Hi Tim,

I've been going through the learning to mock phase this last couple of months and I must say how hard it has been finding up to date documentation. Firstly, I did not realise there was an old and a new way of doing things. 

When searching for documentation, I tend to navigate from the page I've found back to the top level page in the documentation which hopefully gives a good place to start. This page for me, seemed to be here 

Going through selecting random links, I can see most (90%?) of the links seem to have .ReplayAll() calls in there, which (I may be totally wrong here) seems to be the old syntax. 

Seems you've replied to my other email... I'll end this one here :)

cheers,
Stephen


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Rhino.Mocks" group.
To post to this group, send email to rhino...@googlegroups.com
To unsubscribe from this group, send email to rhinomocks+...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/rhinomocks?hl=en
-~----------~----~----~----~------~----~------~--~---


Patrick Steele

unread,
Nov 18, 2009, 7:39:37 AM11/18/09
to rhino...@googlegroups.com
Let me see if I understand exactly what you want (ironically, I
learned RhinoMocks with the AAA syntax and I find it hard sometimes to
follow the record/play syntax). The SearchManager class you're
testing has the following members:

ISearchDAO SearchDAO { get; set; }
IServiceAreaDAO ServiceAreaDAO { get; set; }
ArticleSearchResult SearchForArticles(ArticleSearchCriteria criteria,
int[] serviceAreaIds)

You want to ensure that the when calling SearchForArticles, the
results of any calls made to ServiceAreaDAO.GetById(int) are added to
the criteria.ServiceAreas collection?

--
Patrick Steele
http://weblogs.asp.net/psteele

Goatified Creature

unread,
Nov 18, 2009, 9:50:45 AM11/18/09
to Rhino.Mocks
Exactly! I want!!! However, i was struggling to find an appropriate
Contraint to meet this. I am now looking at the AAA syntax and
attempting to follow the test one thing per test strategy, but it's
difficult when you pick up bad habits!!!

On Nov 18, 12:39 pm, Patrick Steele <patrick.ste...@gmail.com> wrote:
> Let me see if I understand exactly what you want (ironically, I
> learned RhinoMocks with the AAA syntax and I find it hard sometimes to
> follow the record/play syntax).  The SearchManager class you're
> testing has the following members:
>
> ISearchDAO SearchDAO { get; set; }
> IServiceAreaDAO ServiceAreaDAO { get; set; }
> ArticleSearchResult SearchForArticles(ArticleSearchCriteria criteria,
> int[] serviceAreaIds)
>
> You want to ensure that the when calling SearchForArticles, the
> results of any calls made to ServiceAreaDAO.GetById(int) are added to
> the criteria.ServiceAreas collection?
>
> --
> Patrick Steelehttp://weblogs.asp.net/psteele
>
> On Mon, Nov 16, 2009 at 9:52 AM, Goatified Creature
>

Patrick Steele

unread,
Nov 18, 2009, 10:43:54 AM11/18/09
to rhino...@googlegroups.com
If ArticleSearchCriteria has virtual members, I think you could mock
the ServiceAreas collection and set an expectation on the "Add"
method. Assuming you have something like this:

class ArticleSearchCriteria
{
public virtual IList<ServiceArea> ServiceAreas { get; set; }
}

You could create a mock IList<ServiceArea> and set an expectation on
the Add method. Then stub ArticleSearchCritera.ServiceAreas property
to return your mocked IList<ServiceArea> (below is AAA syntax and
typed on-the-fly):

var saList = MockRepository.GenerateMock<IList<ServiceArea>>();
var searchCriteria = MockRepository.GenerateStub<ArticleSearchCriteria>();
s.ServiceAreas = saList; // I think you can just do the assign with AAA syntax

Now tell Rhino mocks you expect an Add of your resultFromDAO:

saList.Expect(c => c.Add(resultFromDAO));

I think that'll get you going.

---
Patrick Steele
http://weblogs.asp.net/psteele

Goatified Creature

unread,
Nov 18, 2009, 11:45:11 AM11/18/09
to Rhino.Mocks
Yep that worked ok.


Now, to change the subject very slightly, now I am understanding the
one assert per test strategy, what tests would be recommended for
testing the following pseaudo method:

public Result SearchAgainstSeveralSystems (string SearchTerm)
{
System1Result = System1.Search(SearchTerm);
System2Result = System2.Search(SearchTerm);

Result result = new Result;
Result.SystemResults.Add(System1Result);
Result.SystemResults.Add(System2Result);
}


my understanding would be make sure you hit the various systems:
search_that_system1_is_searched_against (mocking system1, and stubbing
system2 and result.SystemResults.Add
search_that_system2_is_searched_against (mocking system2, and stubbing
system1 and result.SystemResults.Add


then, maybe 2 searches for
search_that_results_get_added_to_results (stubbing both systems and
mocking the result.SystemResults.Add method expecting two invocations)

Then, should there be a test that asserts the returned result is the
result object? Suppose not as its just a return command but I could
always mistakenly return another Result object.

Alternatively, instead of mocking the result.SystemResults.Add method,
I could simply do a couple of tests that Assert(result.SystemResults
[0], Is.SameAs (a dummy object returned from stubbed systems).

Does this make sense? Problem is that the test doesn't have a handle
to the Result object and therefore, can't have a direct assert against
it.

Cheers


On Nov 18, 3:43 pm, Patrick Steele <patrick.ste...@gmail.com> wrote:
> If ArticleSearchCriteria has virtual members, I think you could mock
> the ServiceAreas collection and set an expectation on the "Add"
> method.  Assuming you have something like this:
>
> class ArticleSearchCriteria
> {
>     public virtual IList<ServiceArea> ServiceAreas { get; set; }
>
> }
>
> You could create a mock IList<ServiceArea> and set an expectation on
> the Add method.  Then stub ArticleSearchCritera.ServiceAreas property
> to return your mocked IList<ServiceArea> (below is AAA syntax and
> typed on-the-fly):
>
> var saList = MockRepository.GenerateMock<IList<ServiceArea>>();
> var searchCriteria = MockRepository.GenerateStub<ArticleSearchCriteria>();
> s.ServiceAreas = saList; // I think you can just do the assign with AAA syntax
>
> Now tell Rhino mocks you expect an Add of your resultFromDAO:
>
> saList.Expect(c => c.Add(resultFromDAO));
>
> I think that'll get you going.
>
> ---
> Patrick Steelehttp://weblogs.asp.net/psteele
>
> On Wed, Nov 18, 2009 at 9:50 AM, Goatified Creature
>

Patrick Steele

unread,
Nov 18, 2009, 1:21:43 PM11/18/09
to rhino...@googlegroups.com
First off, I don't like my original response about mocking IList<> and
expecting a call to add. It exposes too much about the implementation
of your class. If the code is changed to use AddRange() on the
IList<> instead of Add(), the unit test will fail (since Add isn't
called), but the results are still valid.

I think a better approach for testing the SearchForArticles method
would be to stub the DAO's to return the specific items and then,
after calling SearchForArticles, make sure the criteria.ServiceAreas
contain the objects your stubs returned. This tests the behavior of
the method and not the implementation.

As for your other question, I would do something similar: stub
System1.Search and System2.Search to returned pre-determined results
and, after the method call, make sure Result.SystemResults contains
the items the stubbed search objects returned. I assume your
SearchAgainstSeveralSystems is supposed to return the Result object?

Something like this:

var result1 = new System1Result();
var result2 = new System2Result();
var system1 = MockRepository.Stub<System1>();
system1.Stub(s => s.Search("abc")).Returns(result1);
var system2 = MockRepository.Srub<System2>();
system2.Stub(s => s.Search("abc").Returns(result2);

var sut = new Searcher();
var result = sut.SearchAgainstServeralSystems("abc");

Now make sure result.SystemResults contains both result1 and result2.

--
Patrick Steele
http://weblogs.asp.net/psteele
Reply all
Reply to author
Forward
0 new messages