Enumerators

348 views
Skip to first unread message

Heinrich Breedt

unread,
Jul 23, 2010, 3:02:17 AM7/23/10
to NSubstitute
Hi Guys,

Below is code I have for RhinoMocks to stub out a enumerator. Is this
possible in NSubstitute?

var shapesStub = MockRepository.GenerateStub<Shapes>();
var shapes = new List<Shape>();
for (var i = 0; i < count; i++)
{
var shape = MockRepository.GenerateStub<Shape>();
var url = "url" + i;
shape.AlternativeText = url;
shapes.Add(shape);
}
shapesStub.Stub(x =>
x.GetEnumerator()).Return(shapes.GetEnumerator());
application.Stub(x => x.Shapes).Return(shapesStub);

Heinrich

Richard Banks

unread,
Jul 23, 2010, 6:09:41 AM7/23/10
to nsubs...@googlegroups.com
So apart from not quite understanding what you're trying to actually achieve (there's no asserts after all) the following should work:

var shapesStub = Substitute.For<Shapes>();

var shapes = new List<Shape>();
for (var i = 0; i < count; i++)
{
	var shape = Substitute.For<Shape>();

var url = "url" + i;
shape.AlternativeText = url;
shapes.Add(shape);
}
shapesStub.GetEnumerator().Returns(shapes.GetEnumerator());
application.Shapes.Returns(shapesStub);

I'm assuming these are all virtual methods since you're referencing concrete classes not interfaces, as otherwise Rhino wouldn't work either.

--
- Richard Banks (@rbanks54)
blog: http://www.richard-banks.org
podcast: http://www.talkingshopdownunder.com


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




David Tchepak

unread,
Jul 23, 2010, 10:21:01 AM7/23/10
to nsubs...@googlegroups.com
Hi Heinrich,

The code Richard posted works for me. If you have trouble getting it to work for your example can you please post more context?

Regards,
David

On Fri, Jul 23, 2010 at 5:02 PM, Heinrich Breedt <heinric...@gmail.com> wrote:

Heinrich Breedt

unread,
Jul 25, 2010, 10:24:24 PM7/25/10
to nsubs...@googlegroups.com
Hi Guys, so below is the code that is failing for me atm:

i have this in fork at g...@github.com:heinrichbreedt/NSubstitute.git

Heinrich

PS (this is lovely enjoyable vsto work :) )
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace NSubstitute.Acceptance.Specs
{
public interface IApplication
{
Shapes Shapes { get; }
}

public interface Shapes : IEnumerable
{
new IEnumerator GetEnumerator();
Shape get_Item(object Index);
}

public interface Shape
{
string AlternativeText { get; set; }
}

public class EnumeratorExample
{
IApplication application;

[SetUp]
public void Setup()
{
application = Substitute.For<IApplication>();

var shapes = Substitute.For<Shapes>();
var floatingList = new List<Shape>();
for (var i = 0; i < 3; i++)
{
var shape = Substitute.For<Shape>();

var url = "url" + i;
shape.AlternativeText = url;
				floatingList.Add(shape);
}
shapes.GetEnumerator().Returns(floatingList.GetEnumerator());
application.Shapes.Returns(shapes);
}

[Test]
public void foreachExample()
{
var x = 0;
foreach (var shape in application.Shapes)
{
x++;
Assert.IsInstanceOf(typeof (Shape), shape);
}

Assert.That(xIs.EqualTo(3));
}


[Test]
public void castExample()
{
var x = application.Shapes.Cast<Shape>().ToList();
Assert.That(xIs.EqualTo(3));
}
}
}
--
Heinrich Breedt

“Do not wait to strike till the iron is hot; but make it hot by striking.” - William B. Sprague

David Tchepak

unread,
Jul 25, 2010, 11:51:44 PM7/25/10
to nsubs...@googlegroups.com
Hi Heinrich,

The problem is redeclaring GetEnumerator() in Shapes:

new IEnumerator GetEnumerator();

In castExample() the Cast<T>() extension method uses IEnumerable's GetEnumerator(), where you stubbed Shapes.GetEnumerator(). As these are different methods, you get different values returned for the calls.

You can get the test to pass by removing the "new IEnumerator GetEnumerator();" line (it will already have this member from IEnumerable), or by explicitly stubbing out both methods.

Disclaimer: I'd probably try and avoid stubbing out GetEnumerator() in general. It is probably an inappropriate level of intimacy. :)

Hope this helps.

Regards,
David

David Tchepak

unread,
Jul 25, 2010, 11:55:32 PM7/25/10
to nsubs...@googlegroups.com
Sorry, forgot to add that removing the redefinition of GetEnumerator will get castExample() to pass once the assertion is updated:

[Test]
public void castExample()
{
var x = application.Shapes.Cast<Shape>().ToList();
Assert.That(x, Is.EqualTo(_floatingList)); //Criterion was previously "Is.EqualTo(3)"
}

Where _floatingList is the instance created in the [SetUp].

Richard Banks

unread,
Jul 26, 2010, 12:37:37 AM7/26/10
to nsubs...@googlegroups.com
Aww, you beat me to it.  I was going to suggest removing that new GetEnumerator as well :-)

or doing this (as Dave also suggested)
(shapes as IEnumerable).GetEnumerator().Returns(floatingList.GetEnumerator());


Why is it there by the way?  Just curious.

Heinrich Breedt

unread,
Jul 26, 2010, 12:57:11 AM7/26/10
to nsubs...@googlegroups.com
Tx for the reply.

that is VSTO's defintion: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.shapes_members%28v=office.11%29.aspx

real PITA.

is just curious that rhino handles it well enough. But what you are showing me is ok, good enough for me

Heinrich

David Tchepak

unread,
Jul 26, 2010, 1:50:33 AM7/26/10
to nsubs...@googlegroups.com
is just curious that rhino handles it well enough. 

Hmmm, quite right. Works fine with RM. Looking into it now. Thanks for pointing it out.

Cheers,
David 

Garth Kidd

unread,
Jul 25, 2010, 11:07:15 PM7/25/10
to NSubstitute
Heinrich;

Make sure you mock out the correct GetEnumerator. If your subject
under test uses IEnumerable rather than IEnumerable<T>, you'll need to
downcast your substitute to IEnumerable when calling Returns().

See the code below:

In TryEnumerableOfT_With_OfType, the final line crashes with
NullReferenceException because System.Linq.Enumerable.OfType extends
IEnumerable, not IEnumerable<T>.

In TryEnumerableOfT_With_OfType_UsingCasting, we downcast the
substitute to IEnumerable when calling Returns(). The call to OfType()
succeeds, and we get the results we expect.

Yours,
Garth.

[Explicit("Tests a dependency, not our code.")]
[TestFixture]
public class Test_NSubstitute_WithEnumerables {
[Test]
public void TryEnumerableOfT() {
List<object> actual = new List<object>() { "fnord" };
IEnumerable<object> subject =
Substitute.For<IEnumerable<object>>();
subject.GetEnumerator().Returns(actual.GetEnumerator());

List<object> enumerationResults = subject.ToList();

subject.Received().GetEnumerator();
Assert.AreEqual(actual, enumerationResults);
}

[Test]
[ExpectedException(typeof(NullReferenceException))]
public void TryEnumerableOfT_With_OfType() {
List<object> actual = new List<object>() { "fnord" };
IEnumerable<object> subject =
Substitute.For<IEnumerable<object>>(); // oops!
subject.GetEnumerator().Returns(actual.GetEnumerator());

var enumerationResults =
subject.OfType<string>().ToList(); // you did it wrong
}

[Test]
public void TryEnumerableOfT_With_OfType_UsingCasting() {
List<object> actual = new List<object>() { "fnord" };
IEnumerable<object> subject =
Substitute.For<IEnumerable<object>>();
((IEnumerable)
subject).GetEnumerator().Returns(actual.GetEnumerator()); // better

var enumerationResults =
subject.OfType<string>().ToList();

((IEnumerable) subject).Received().GetEnumerator();
Assert.AreEqual(actual, enumerationResults);
}

[Test]
public void TryGenericInterfaceDerivedFromEnumerableOfT() {
List<object> actual = new List<object>() { "fnord" };
var subject =
Substitute.For<IEnumerateAndAddValue<object>>();
subject.GetEnumerator().Returns(actual.GetEnumerator());

List<object> enumerationResults = subject.ToList();

subject.Received().GetEnumerator();
Assert.AreEqual(actual, enumerationResults);
}

public interface IEnumerateAndAddValue<T> : IEnumerable<T> {
void AddValue();
}

[Test]
public void TryNonGenericInterfaceDerivedFromEnumerableOfT() {
List<object> actual = new List<object>() { "fnord" };
var subject =
Substitute.For<IEnumerateObjectsAndAddValue>();
subject.GetEnumerator().Returns(actual.GetEnumerator());

List<object> enumerationResults = subject.ToList();

Assert.AreEqual(actual, enumerationResults);
subject.Received().GetEnumerator();
}

public interface IEnumerateObjectsAndAddValue :
IEnumerable<object> {
void AddValue();

David Tchepak

unread,
Jul 28, 2010, 8:26:29 AM7/28/10
to nsubs...@googlegroups.com
Hi Heinrich,

I've looked into this and I'm reasonably confident that this is actually a bug in Rhino Mocks. A convenient bug in this case, but a bug nonetheless. :)

I haven't been able to confirm it yet, but here's my post to the RM list to ask about it, including examples as to why I think it may be a bug:

(or http://bit.ly/d9rWLN if wrapping kills the link)

If I'm way off base and RM's behaviour is actually correct, please let me know! :)

Regards,
David

Heinrich Breedt

unread,
Jul 28, 2010, 6:11:59 PM7/28/10
to nsubs...@googlegroups.com
Hi David, i noticed the post. I think i agree with you. Tx for the effort mate
Reply all
Reply to author
Forward
0 new messages