1

I'm writing a unit test with a mock and I'm having trouble writing it successfully. One of the properties is a collection and I need to reference it when setting an expectation for the mock. Right now the expectation statement throws a null. Here's what it roughly looks like.

IFoo myMock = MockRepository.GenerateMock<IFoo>();
List<Entity> col = new List<Entity>();
Entity entity = new Entity();

myMock.Expect(p => p.FooCollection).Return(col);
myMock.Expect(p => p.FooCollection.Add(entity)); // throws null exception here

I'm new to rhino mocks and have a feeling I'm not doing this correctly. Is there anyway else to properly instantiate the collection? Possibly without an expectation like I have above?

Update
I think I'm having the problem because the interface I defined specifies the collection as readonly.

interface IFoo
{
    List<Entity> FooCollection { get; }
}
Jeff LaFay
  • 12,882
  • 13
  • 71
  • 101

2 Answers2

1

I'm not overly familiar with Rhino Mocks, but I think your expectations aren't actually hooked up until you call .Replay() - the mocking methodology you hint at in your example looks more like Moq to me.

That said, I think you're doing something more fundamentally wrong here. Exactly what is it that you want to test? Is it the p object, or something on List<Entity>? If what you actually want to test is that p.YourMethodUnderTest() actually adds entity to the collection, you probably just want to setup p.FooCollection to return your list, and then verify that your list contains the entity object.

// Arrange
IFoo myMock = MockRepository.GenerateMock<IFoo>();
List<Entity> col = new List<Entity>();
Entity entity = new Entity();

myMock.Expect(p => p.FooCollection).Return(col);
// myMock.Expect(p => p.FooCollection.Add(entity)) - skip this

// Act
p.YourMethodUnderTest(entity);

// Assert
Assert.IsTrue(col.Contains(entity)); // Or something like that
Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • I don't know why I didn't think of that! I think I was asking too much from rhino mocks. Thanks so much for your solution. – Jeff LaFay Jun 07 '11 at 21:12
0

Instead of mocks you should use stubs, like:

IFoo myMock = MockRepository.GenerateStub<IFoo>();
myMock.FooCollection = col;

Also, you are setting the expectation on a real object (collection.Add()), which won't really work. You can solve this by making your FooCollection property type of IList instead of a concrete List.

Using concrete collection types as parameters is a code smell anyway (and I suggest using FxCop to teach you such things).

Igor Brejc
  • 18,714
  • 13
  • 76
  • 95
  • The collection is readonly so you can't directly assign it like you did in your example. Is it a code smell because I expose the collection as a property? I could see keeping it a private field and adding an AddEntity() method as beneficial because now that I look back at my code, there is coupled code where the client code does things with the entity after it is added to the collection. – Jeff LaFay Jun 08 '11 at 14:48
  • You're right about the read-only collection, my code would not work. As for the code smell, I meant this: http://stackoverflow.com/questions/387937/why-is-it-considered-bad-to-expose-listt – Igor Brejc Jun 08 '11 at 18:18
  • I'm not sure I totally agree with the dominant answers for that question but I do think I needed to keep from exposing my collection. The answers mentioned that List is bloated and IList is not so bloated. Well, yeah that's how it should be. Your IList variable still points to a List, so it's not less "bloated". – Jeff LaFay Jun 08 '11 at 18:32
  • By exposing `IList<>` you are actually making it easier for an implementation to use something other than `List<>` - like `Entity[]` array, for example. The idea is to use interface to define contracts, and not to enforce implementation details in these contracts. Specifying a concrete collection type (like `List`) is enforcing an implementation detail without the real need. And by using interfaces you are actually making it easier to mock things. – Igor Brejc Jun 09 '11 at 03:55
  • As for your suggestion on `AddEntity()` method instead of exposing the collection, it's a good suggestion. See Law of Demeter (http://en.wikipedia.org/wiki/Law_of_Demeter) – Igor Brejc Jun 09 '11 at 03:58
  • Thanks for your perspective. I think I grew a little more as a developer yesterday :) – Jeff LaFay Jun 09 '11 at 12:27