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
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
(I don't know if this is, or should be possible)

I have this method:
void Method(IDictionary<string, string> stuff);


used in this code:
...
Dictionary<string, string> stuff = new Dictionary<string, string>();
Method(stuff);
if (stuff.Count > 0)
...


How do I mock Method in order for stuff to have count greater than zero before the execution of the if statement?
asked by paulo.morgado (11k points)

10 Answers

0 votes
Looks like you can do this by using a MockObject and handling the IMethodSettings.MockMethodCalled event.

namespace MockMethodBehavior
{
  public class MethodContainer
  {
    public void Method(IDictionary<string, string> stuff)
    {
      // Doesn't matter what's here.
    }

    public void CallingMethod()
    {
      Dictionary<string, string> stuff = new Dictionary<string, string>();
      this.Method(stuff);
      if (stuff.Count > 0)
      {
        throw new InvalidOperationException();
      }
    }
  }

  [TestFixture]
  [VerifyMocks]
  public class UnitTests
  {
    [Test]
    [ExpectedException(typeof(System.InvalidOperationException))]
    public void CountGreaterThanZero()
    {
      MockObject<MethodContainer> mockContainer = MockManager.MockObject<MethodContainer>();
      mockContainer.MethodSettings("Method").MockMethodCalled += new MockMethodCalledEventHandler(SimulateMethodExecution);
      mockContainer.ExpectCall("Method");

      mockContainer.Object.CallingMethod();
    }

    void SimulateMethodExecution(object sender, MockMethodCallEventArgs e)
    {
      IDictionary<string, string> stuff = e.SentArguments[0] as IDictionary<string, string>;
      stuff.Add("key1", "value1");
    }
  }
}
answered by tillig (6.7k points)
0 votes
Thanks Travis.

And if you are using Natural TypeMocks™:

[TestMethod]
[VerifyMocks]
public void TestMethod2()
{
    MethodContainer container = RecorderManager.CreateMockedObject<MethodContainer>();
    
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
        container.Method(null);
        recorder.IgnoreArguments();
        RecorderManager.GetLastRecordedMock().MockMethodCalled += delegate(object sender, MockMethodCallEventArgs e)
            {
                IDictionary<string, string> stuff = e.SentArguments[0] as IDictionary<string, string>;
                stuff.Add("key1", "value1");
            };
    }

    container.CallingMethod();
}


And the use of a anonymous method makes the test more readable.
answered by paulo.morgado (11k points)
0 votes
If I change the method signature to return a NameValueCollection instead of void:

NameValueCollection Method(IDictionary<string, string> stuff);


RecorderManager.GetLastRecordedMock() returns the NameValueCollection value instead of the MethodContainer.

But is the return value is a bool, string or DataTime, it works fine? What's happening?
answered by paulo.morgado (11k points)
0 votes
It actually makes a sort of logical sense:
  • Certain mscorlib stuff can't be mocked. Presumably bool, string, and DateTime are in that lot. NameValueCollection isn't.
  • The method call gets mocked and, after the method gets called, the return value from that method gets mocked...
  • ...so the last recorded mock really is the return value.

That said, just because it's technically logical doesn't mean it's pretty.

Perhaps it'd just be easier if you used the reflective mechanism for now?

(I'll wait for some TypeMock folks to chime in on this one. I'd assume there's some natural mock way to do this, too, but maybe GetLastRecordedMock isn't it...)
answered by tillig (6.7k points)
0 votes
What we need is a GetLastRecordedMocks() with a stack of the last mocks. Each umockable class would be a null as well as the return value of GetLastRecordedMock().
answered by paulo.morgado (11k points)
0 votes
I came up with a better suggestion:

class RecordExpectations
{
    ...

    public IMockBehavior ExpectAndCall(
        object mockedStatements,
        object returnValue,
        MockMethodCalledEventHandler mockMethodCalled
    );

    public IMockBehavior Call(
        MockMethodCalledEventHandler mockMethodCalled
    );

    ...
}
answered by paulo.morgado (11k points)
0 votes
Hi all,

What do you think of this way:

public object ReturnRefValues(object[] parameters, object context) 
{
    Dictionary<string, string> dummy = parameters[0] as Dictionary<string, string>;
    dummy.Add("", "");
    return null;
}

[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void stam()
{
    Mock mock = MockManager.Mock<MethodContainer>();
    mock.ExpectAndReturn("Method",new DynamicReturnValue(ReturnRefValues));

    MethodContainer target = new MethodContainer();
    target.CallingMethod();
}

and in Natural:
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void stam_natural()
{
    using (RecordExpectations rec = new RecordExpectations())
    {
        MethodContainer mock = new MethodContainer();
        mock.Method(null);
        rec.Return(new DynamicReturnValue(ReturnRefValues));
    }
    MethodContainer target = new MethodContainer();
    target.CallingMethod();
}


In any case I really liked Paulo idea for the ExpectAndCall API.

:!: Its worth mentioning that for cases where the sent argument is a ref/out the Assign API can be used to change the value of argument:
mock.ExpectCall("Method").Args(new Assign(fakeValue));
answered by lior (13.2k points)
0 votes
Cool.

And what if I the expectation is to be set on a method that has no return value?

And I sitll haven't figured out exactly what Args and When are for.
answered by paulo.morgado (11k points)
0 votes
Hi,

Actually the example I posted works fine on the void returning methods as well. And yes, I know the ExpectAndReturn usage is quite misleading here which was one of the reason I liked the API so much.

The main usage of "Args" is to make sure arguments sent into a method are the same as the one which were expected. (same effect as using CheckArguments in Natural).

The When API is used for "Conditional mocking". For example let say you want to mock a call to "Method" but only when the input argument value equals to 5 while the rest of the call should be executed normally:
mock.ExpectCall("Method").When(5);

:arrow: For more complex conditions we use the Check class
answered by lior (13.2k points)
0 votes
Actually the example I posted works fine on the void returning methods as well.


Yes. I hadn't noticed.

The main usage of "Args" is to make sure arguments sent into a method are the same as the one which were expected. (same effect as using CheckArguments in Natural).

The When API is used for "Conditional mocking". For example let say you want to mock a call to "Method" but only when the input argument value equals to 5 while the rest of the call should be executed normally:

mock.ExpectCall("Method").When(5); 


For more complex conditions we use the Check class


I we need more sample code, because that's an area where intellisense can't help.

.Args(12, "test", DateTime.Now)


may seem more readable, but, looking at it now, I think I would prefer something like:

.Args(Check.IsEqual(12), Check.IsEqual("test"), Check.IsNow)


I like intellisense.
answered by paulo.morgado (11k points)
...