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
Below is an example case where having the expectations turned on within the context of DynamicReturnValue delegate calls would be very beneficial, for constructing stubs.

In this example Entity and EntityColl classes are to be mocked because they are from a third party assembly requiring a server enviroment etc.
EntityColl class is a dictionary collection with its own add and get methods.

I have added inline comments within the code below that explains how having the expectations turned off inside DynamicReturnValue methods causing problems. I think the code is explanatory enough, if needed I can give more explanation.

The mocked objects are avaliable in the DynamicReturnValue context, but its mocked methods/properties aren't. Why not have the mocked methods
avaliable also?

using System.Collections.Generic;
using NUnit.Framework;
using TypeMock;
namespace UnitTesting
{

class Entity
{
string _name;
public string Name { get { return _name;}}
int _id;
public int Id { get { return _id;}}
public Entity(string name, int id)
{
_name = name;
_id = id;
}
}

class EntityColl
{
// this class holds a dictionary of Entities
private EntityColl()
{

}

public Entity Add(string name, int id)
{
// supposed to create an Entity object and adds it to the internal dictionary
return null; // just get it to compile, implementation here is not important
}
public Entity GetById(int id)
{
// supposed to find in the dictionary the Entity object that has this id and return it
return null; // just get it to compile, implementation here is not important
}

public Entity this[string index]
{
get
{
return null; // just get it to compile, implementation here is not important
}
}
}
[TestFixture]
public class TestClass
{
class EntityCollStub
{
private Dictionary<string, Entity> _entities;
private MockObject _entityCollMock;
public EntityCollStub()
{
_entities = new Dictionary<string, Entity>();
_entityCollMock = MockManager.MockObject(typeof (EntityColl));
_entityCollMock.ExpectGetIndexAlways(new DynamicReturnValue(IndexerGetValue));
_entityCollMock.AlwaysReturn("Add", new DynamicReturnValue(AddReturnValue));
_entityCollMock.AlwaysReturn("GetById", new DynamicReturnValue(GetByIdReturnValue));
}
public EntityColl Stubbed
{
get { return (EntityColl)_entityCollMock.MockedInstance; }
}

object IndexerGetValue(object[] parameters, object context)
{
return _entities[parameters[0].ToString()];
}
object GetByIdReturnValue(object[] parameters, object context)
{
int id = (int)parameters[0];
// this never finds the entity within the dictionary
// because the entities inside the dictionary are mocked objects
// and within this DynamicReturnValue context the expectations
// are turned off and they all return null or empty,
// as a result the method always returns nulls... incorrectly.
foreach (Entity entity in _entities.Values)
{
if (entity.Id == id)
{
return entity;
}
}
return null;
}
object AddReturnValue(object[] parameters, object context)
{
MockObject entityMock = MockManager.MockObject(typeof(Entity));
entityMock.ExpectGetAlways("Name", parameters[0].ToString());
entityMock.ExpectGetAlways("Id", parameters[1]);
Entity mocked = (Entity)entityMock.MockedInstance;
// fails in the following line, because mocked.Name returns null!
_entities.Add(mocked.Name, mocked);
return mocked;
}
public void AddEntityHelper(Entity entity)
{
_entities.Add(entity.Name, entity);
}
}
[Test]
public void TestFails()
{
EntityCollStub entityCollStub = new EntityCollStub();
EntityColl entityColl = entityCollStub.Stubbed;

// fails in EntityCollStub.AddReturnValue() method because the mock object's expectations that is
// created within the AddReturnValue is not executed.
Entity entity = entityColl.Add("first entity", 1);

}
[Test]
public void TestFails2()
{
MockObject entityMock1 = MockManager.MockObject(typeof (Entity));
entityMock1.ExpectGetAlways("Name", "some entity");
entityMock1.ExpectGetAlways("Id", 1);

EntityCollStub entityCollStub = new EntityCollStub();
// this time use the helper Add method to add the mocked
// entity to the stub
entityCollStub.AddEntityHelper((Entity)entityMock1.MockedInstance);
EntityColl entityColl = entityCollStub.Stubbed;
// this also fails, because inside EntityCollStub.GetByIdReturnValue
// the mocked entity that was added above has all the expectations turned off
// they all return null or empty
Assert.AreEqual("some entity", entityColl.GetById(1));


}
[SetUp]
public void Setup()
{
MockManager.Init();
}
}
}
asked by phazer (4k points)

9 Answers

0 votes
I just checked this out and you're right. What's really weird is that if you update the AddReturnValue method so you can see what's up..
object AddReturnValue(object[] parameters, object context) 
{
   MockObject entityMock = MockManager.MockObject(typeof(Entity)); 
   entityMock.ExpectGetAlways("Name", parameters[0].ToString()); 
   entityMock.ExpectGetAlways("Id", parameters[1]); 
   Entity mocked = (Entity)entityMock.MockedInstance; 
   Console.WriteLine("Adding {0} [{1}].", mocked.Name, parameters[0]);
   _entities.Add(mocked.Name, mocked); 
   return mocked; 
}


(Notice my Console.WriteLine in there...)

You can see that even right in that method the mocked.Name doesn't return the correct value. If you watch the trace utility, you can see all the expectations getting set up, but they don't get called. The Console.WriteLine yields:

Adding [first entity].

And looking at the tracer, there's an expectation for Entity.Name that is set up but is never called, even though I'm calling it right there in the Console.WriteLine immediately after it's set up. Weird.
answered by tillig (6.7k points)
0 votes
Hi,
While you are inside the Dynamic Return Value you are allowed to create mocks and expectations, but you cannot run these mocks.
See Tips in the Dynamic Returns topic.

The reason for this is that you are actually running inside a mocked method when you are in the Dynamic Return Value delegate.
:arrow: I have created a request for this feature.
answered by eli (5.7k points)
0 votes
I had seen in the documentation that expectations are not running inside DynamicReturnValue delegate, that is why I put it here as a feature request.

Just in case to make it more clear. Not only the mocks and expectations created with a Dynamic Return Value method return null/Empty, but any other mock, which might have been created before.

When I did a search on this at this forum, I had found an older post saying the expectations are turned off inside Dynamic Return value, because it was prone to recursive infinite loops. Could it be made configurable in that case? Like a property on MockManager, or some other place. Because having the mocks fully running with these DynamicReturnValues, makes them very versatile when building stubs.
answered by phazer (4k points)
0 votes
I just ran into an interesting situation where, again, this would be helpful. I had totally forgotten that this wasn't the case and went through debugging things until I remembered, "Oh, yeah, mocks don't run inside DynamicReturnValues!" Is this still on the list of possible features for a future release?
answered by tillig (6.7k points)
0 votes
Hi Travis,

This is unfortunately still the case, and still on our wish list. There is a possible work around opened by the latest version - duck-type swapping can include mocking in the class being swapped to.
Consider this and let me know if it helps:


public class ToReplace
{
   public int Foo(double d)
   {
      // some complicated code 
   }

   // a lot more methods
}

public class Replacement
{
   public int Foo(double d)
   {
      // some predictable calculation
   }
}

[TestMethod]
public void Test()
{
   ToReplace target = new ToReplace();;
   Isolate.Swap.CallsOn(target).WithCallsTo(new Replacement);

   target.Foo(5.5); // should return the predictable value
}
answered by doron (17.2k points)
0 votes
Looking at it, what I left out of my example is that the predictable calculation in the replacement class can include mocking.

Thanks,
Doron
Typemock support
answered by doron (17.2k points)
0 votes
We may have to try this later. We are on Isolator 5.1.0, which doesn't have the duck typing, and we have yet to schedule the upgrade for 5.1.1.

The thing we're trying to mock is a generic base class with a protected static method, like:

public abstract FooBase<T>
{
  protected static void Execute(Action<T> action)
  {
    // some initialization code happens here that we want
    // to mock, like this:
    T obj = new T();
    obj.DoSomeInitialization();
    obj.SomeProperty = GetSomeValueFromConfig();

    // and we just want to skip all of that and run
    // the action because that's the part we want to
    // test... and it's an anonymous delegate with a
    // closure, so we can't just pull it out and test it
    // separately....
    action(T);
  }
}

public class DerivedClass : FooBase<ObjType>
{
  // here's the method we actually want to test:
  public Guid DoSomething()
  {
    // stuff happens in here that looks like:
    Guid returnValue;
    Execute(delegate(ObjType o)
    {
      // work happens and somewhere in here
      // we see something like:
      returnValue = o.SomeMethod();
    }
    return returnValue;
  }
}


So, as you can see, we have a bit of a tricky situation. The static belongs to a closed generic base type even though it's declared on an open generic base type, it's nonpublic, and the action we're performing is a closure. The initial desire was to set up a DynamicReturnValue like:

ObjType obj = RecorderManager.CreateMockedObject<ObjType>();
DynamicReturnValue executeReturnValue = new DynamicReturnValue((parameters, context) =>
{
  var action = parameters[0] as Action<ObjType>;
  Assert.IsNotNull(action);
  action(obj);
  return null;
});
MockObject<FooBase<ObjType>> mockBase = MockManager.MockObject<FooBase<ObjType>>();
mockBase.CallStatic.ExpectAndReturn("Execute", executeReturnValue);


That way we'd have a reference to the object being passed in, we could skip the initialization calls in the Execute method, but still execute the anonymous delegate and verify functionality there. Unfortunately, since (in this example) ObjType has to have some methods mocked on it inside the anonymous delegate, we need to have mocks running, so this doesn't work - when we hit the DynamicReturnValue, mocks "shut down" and it actually tries to run the methods on ObjType.

Anyway, yet another case where this would be handy. I'm not sure how we'd do this with the duck typing solution - can you swap in an object with a matching protected static method and have that work?

BTW, if you try to use mocks inside a DynamicReturnValue, you see some interesting debugger interaction if you're running the tests through the debugger. A method will be outlined as though it's being mocked, but you'll actually be stepping through the code because in reality it's not being mocked. Causes for a little confusion, but no showstopper.
answered by tillig (6.7k points)
0 votes
BTW, this situation that Travis is talking about is the same one that I was talking about at https://www.typemock.com/community/viewt ... =4235#4235. Check there for more info.
answered by travislspencer (1.3k points)
0 votes
Hi Travis,

Here's the code that would work:

           ObjType obj = RecorderManager.CreateMockedObject<ObjType>();
           DynamicReturnValue executeReturnValue =
                new DynamicReturnValue((parameters, context) =>
                                           {
                                               var action =
                                                   parameters[0] as Action<ObjType>;
                                               Assert.IsNotNull(action);
                                               action(obj);
                                               return null;
                                           });
           var mockBase = MockManager.Mock<FooBase<ObjType>>();
           mockBase.ExpectAndReturn("Execute", executeReturnValue);


The difference is using Mock (or MockAll if we're talking multiple instance) instead of MockObject, since the object is not used right away - we're faking a future one.
The other difference that doesn't matter is the use of CallStatic, which is redundent.

Let me know if this works for you.
answered by gilz (14.5k points)
...