chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
We have "Domain" objects in our application that represent an object graph of information that is loaded from a DB. I have been trying to use reflective TypeMock.

For example, say I am trying to mock a Car. I might have the following reference in my code. There are separate classes for Car, Engine, Piston, and PistonHead.

Car.Engine.Pistons[0].PistonHead


IF I "load" a car from the DB, the object graph under it gets loaded. I want to avoid that in tests. So, I not only want to mock the Car, but also have its Engine property return a mockEngine, which then will present a mock Pistons list, etc.

Mock mockCar = MockManager.Mock(typeof(Car));
Mock mockEngine = MockManager.Mock(typeof(Engine));

mockCar.ExpectGetAlways("Engine", mockEngine);


I begain setting this up and immediately got an error:
TypeMock.TypeMockException: 
*** No method get_Engine in type MyNamespace.Car returns TypeMock.MockObject`1


How do you mock an object graph if you cannot specify that a mocked object's properties should return other mock objects?

Also, I do not see from the documentation, or in the forums any Expect... call that would handle an indexed property such as Car.Engine.Pistons[0]. How do you mock that case?
asked by bjsafdie (680 points)

9 Answers

0 votes
[UPDATED 2/22/08: Fixed the example to use MockObject instead of Mock.]

I think you actually want to do this:

Mock mockCar = MockManager.Mock(typeof(Car));
MockObject mockEngine = MockManager.MockObject(typeof(Engine));
mockCar.ExpectGetAlways("Engine", (Engine)mockEngine.Object);


You want the instance being mocked to be returned, not the mock itself. Note that the first instance of Car that gets created will be the one that participates in the mocking above - that's what "Mock" is: mock the next instance.

It's a little cleaner with generics:

Mock<Car> mockCar = MockManager.Mock<Car>();
MockObject<Engine> mockEngine = MockManager.MockObject<Engine>();
mockCar.ExpectGetAlways("Engine", mockEngine.Object);


Of course, it's far simpler to just do a mock chain in Natural mocks and you don't have to worry about any of that:

Car myCar = new Car();
PistonHead substitute = new PistonHead();
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
  PistonHead dummy = myCar.Engine.Pistons[0].PistonHead;
  recorder.Return(substitute);
  recorder.RepeatAlways();
}


I created a Car that I'm going to run my tests on ("myCar") and I created the PistonHead that I expect to be returned for the first Piston in the car ("substitute"). Then I used Natural mocks to execute the whole statement and say "whenever I ask for this, always give me the substitute value." I didn't have to set up the whole object graph.

You can learn more about chained calls in the TypeMock Developer Guide under "Using TypeMock Isolator -> Natural Mocks -> Chaining Statements."

(I'm not sure how to link you to that page and still retain the table of contents. Here's a direct link without the TOC.)
answered by tillig (6.7k points)
0 votes
You should use MockObject (that will create an Instance of the mocked type) and return that mocked object.
So your test will look like:

Mock<Car> mockCar = MockManager.Mock<Car>();
MockObject<Engine> mockEngine = MockManager.MockObject<Engine>();
mockCar.ExpectGetAlways("Engine", mockEngine.Object);


Here is the link with the TOC: Chaining Statements
answered by eli (5.7k points)
0 votes
Hi,

Using Mock and its MockedInstance property will not work in this case.
MockedInstance is set only after the real instance that the mock is attached to is created.

In order to created a fake value to return you will need to create and use a MockObject (on the difference between Mock and MockObject see this blog)
Mock mockCar = MockManager.Mock(typeof(Car)); 
MockObject mockEngine = MockManager.MockObject(typeof(Engine)); 
mockCar.ExpectGetAlways("Engine", (Engine)mockEngine.Object); 


Of course as Travis showed its much easier to just use Natural mocks.

regarding your other question, check out our examples page under Mocking indexers .
The API you are looking for is ExpectGetIndex seehere

:!: BTW the last link show the url to use in order to link to the guide and still see the table of content.
answered by lior (13.2k points)
0 votes
First, thank you all for your help. I appreciate the quick turnaround and patience with a newbie. I am trying to find things in the docs before I take up yout time here, but as with all newbies, I am trying to absorb a lot all at once and get my project done at the same time. ;-)

Sadly, I cannot use natural mocks, because I am currently using the community edition. We did not get TypeMock into the budget, so we will have to prove things out with reflective mocking to help with the justification in the long term. So, much of the documentation that emphasizes Natural Mocks is of no help. The doc does not always provide equivalent reflective mock examples.

As for your advice about the indexed property, I had seen the ExpectGetIndex calls, but they did not seem to show any way of associating the indexer with a property. What I expected to find was something like this:
 mockEngine.ExpectGetIndexedPropertyAlways("Pistons". mockPiston.Object);


In your example, I could mock the Pistons property and then tell it to expect an indexed access. However, the Pistons property is of type ReadOnlyCollection<Piston> and only the Enterprise version supports mocking mscorlib classes, according to the exception I got.

Is there another way to do this?
answered by bjsafdie (680 points)
0 votes
Hi,


The ExpectSetIndex is called on the mock of the container, and it returns an interface that allows you to specify the index and how to check arguments. So it actually does what you are looking for, if I read this correctly.

Please look at: https://www.typemock.com/Docs/UserGuide/ ... oad_2.html

Here's another way:

An indexed property in C# is just a substitute to the method "get_item(index)". So if you need to mock the Pistons[x], it is equivalent to :

Mock<Pistons> pistons = MockManager.Mock<Pistons>;
pistons.ExpectAndReturn("get_Item", 5);


Let me know if this helps.
answered by gilz (14.5k points)
0 votes
I will see if I can make that work, but I feel that maybe there is some confusion. Perhaps this will help:

Classes:
public class CarClass 
{
    public EngineClass Engine { get{...} set{...} }
    ...
}

public class EngineClass
{
    public ReadOnlyCollection<PistonClass> Pistons { get{...} }
    ...
}

public class PistonClass
{
    public PistonHeadClass PistonHead { get{...} set{...} }
    ... 
}


In the reference,
MyCar.Engine.Pistons[0].PistonHead

the property Pistons is of type ReadOnlyCollection<PistonClass>. So, to mock the container, I did try

 mockPistonsCollection = Mock.MockObject(typeof(ReadOnlyCollection<PistonClass>));


This is when I got the exception saying that you cannot mock mscorlib classes unless you have the enterprise version of TypeMock. Is there an alternative? Or, am I somehow being overly obtuse?

Thanks again,
--BJ
answered by bjsafdie (680 points)
0 votes
Oops - my bad on the MockObject vs. Mock thing (above). I guess that's the price I pay for writing code off the top of my head. :)

I updated my original post to be correct so folks reading this in the future won't get confused and have to correct themselves later.
answered by tillig (6.7k points)
0 votes
BJ,

There's the rub. ReadOnlyCollection is indeed a type from mscorlib. And Isolator cannot mock types defined in mscorlib.

A workaround might be to define a wrapper type around ReadOnlyCollection<PistonClass>, say PistonCollection:

public class PistonCollection
{
    private ReadOnlyCollection<PistonClass> pistons;
    ...
}


Which its methods you can mock.
Let me know if it works for you.
answered by gilz (14.5k points)
0 votes
Hi,
Another approach might be to create a dummy ReadOnlyColelction and put necessary data in it, instead of actually mocking it.
this will also allow you to do your test but you wont need to changes your code.
for example:
Ilist<Piston> fakeList = new Ilist<Piston>();
fakeList.Add(FakePiston);
ReadOnlyCollection fakeCollection = new ReadOnlyCollection(fakeList);

and now use fakeCollection and return it from the call to MyCar.Engine
answered by lior (13.2k points)
...