How to test if correct Action<T> was passed

393 views
Skip to first unread message

Rastislav Svoboda

unread,
Jun 10, 2010, 2:01:25 PM6/10/10
to Rhino.Mocks
Hi all

I have these two interfaces:

public interface IEntry
{
void DoSomething();
void DoSomethingElse();
}

public interface IListOfEntries
{
void Add(IEntry entry);
void Remove(IEntry entry);
void ForEachEntry(Action<IEntry> action);
}

and some class that I want to test:

public class Handler
{
private readonly IListOfEntries _list;

public Handler(IListOfEntries list)
{
_list = list;
}

public void HandleSomethingHappened()
{
_list.ForEachEntry(entry => entry.DoSomething());
}

public void HandleSomethingElseHappened()
{
_list.ForEachEntry(entry => entry.DoSomethingElse());
}
}

Here are the tests:

[TestMethod]
public void AssertingThatDoSomethingWasCalledForEachEntry()
{
IListOfEntries entriesMock =
MockRepository.GenerateMock<IListOfEntries>();
Handler handler = new Handler(entriesMock);

handler.HandleSomethingHappened();

entriesMock.AssertWasCalled(x => x.ForEachEntry(entry =>
entry.DoSomething()));
}

[TestMethod]
public void AssertingThatDoSomethingElseWasCalledForEachEntry()
{
IListOfEntries entriesMock =
MockRepository.GenerateMock<IListOfEntries>();
Handler handler = new Handler(entriesMock);

handler.HandleSomethingElseHappened();

entriesMock.AssertWasCalled(x => x.ForEachEntry(entry =>
entry.DoSomethingElse()), o => o.IgnoreArguments());
}


Why the first test fails?

Second works - when I ignore the arguments.

But then if method HandleSomethingElseHappened()
calls by mistake (copy & paste):

_list.ForEachEntry(entry => entry.DoSomething());

instead of DoSomethingElse()
I will not know that :-(

Any ideas?
Thanx for answers
Rastislav

Patrick Steele

unread,
Jun 10, 2010, 6:23:50 PM6/10/10
to rhino...@googlegroups.com
Remember that lambdas are nice shortcuts for anonymous methods -- and
anonymous methods are a compiler shortcut for us writing a standalone
method. If we "reverse engineer" your code into what it will look
like to the compiler, you'll see something like this:

public class Handler
{
...
public void HandleSomethingHappened()
{
_list.ForEachEntry(OnAction);
}

private void OnAction(IEntry entry)
{
entry.DoSomething();
}
...
}

And your test code will have something similar:

[TestMethod]
public void AssertingThatDoSomethingWasCalledForEachEntry()
{
IListOfEntries entriesMock = MockRepository.GenerateMock<IListOfEntries>();
Handler handler = new Handler(entriesMock);

handler.HandleSomethingHappened();

entriesMock.AssertWasCalled(x => x.ForEachEntry(OnAction));
}

private void OnAction(IEntry entry)
{
entry.DoSomething();
}

As you can see, once all these lambdas are compiled into something the
compiler can use, they're actually two totally different methods --
which is why your unit test is failing. You're calling two different
methods (one is in your Handler class and one is in the Unit Test).

I think you need to re-think how to test this situation. In writing a
unit test for Handler.HandleSomethingHappened(), you'll just want to
make sure that it calls IList.ForEachEntry(). A separate unit test on
the implementation of IList.ForEachEntry() should make sure that the
Action<T> passed in is executed for each item.

Hope this helps.

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

> --
> 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.
>
>

Tim Barcz

unread,
Jun 10, 2010, 9:20:06 PM6/10/10
to rhino...@googlegroups.com, rhino...@googlegroups.com
Helped me! Thanks for the refresher

On Jun 10, 2010, at 5:23 PM, Patrick Steele <patrick...@gmail.com>
wrote:

Reply all
Reply to author
Forward
0 new messages