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
I'm doing some tests that mock classes that implement ToString().

It's very annoying because I have to record expectations for ToString() even when the code being tested doesn't call ToString().

Is there any guidance or workaround for this?
asked by paulo.morgado (11k points)

5 Answers

0 votes
Hi,

Im not sure I understand what you mean.
If a tested code doesnt call the method you shouldn't mock it.

Can you please tell me what exception you are getting? (and maybe post the test code)

:idea: use the tracer in order to see calls made on mocked objects
answered by lior (13.2k points)
0 votes
The exception is:

TypeMock.VerifyException:
TypeMock Verification: Unexpected Call to Esi.FlexView.PL.Web.ServiceFlow.ServiceFlow.ToString().


The stack trace is:

at TypeMock.MockManager.a(String A_0, String A_1, Object A_2, Object A_3, Boolean A_4, Object[] A_5)
at TypeMock.InternalMockManager.getReturn(Object that, String typeName, String methodName, Object methodParameters, Boolean isInjected, Object p1, Object p2, Object p3)
at MockIServiceFlowNavigationController.CanNavigateTo(IServiceFlow , Int32 , Boolean& )
at Esi.FlexView.PL.Web.ServiceFlow.ServiceFlow.CanNavigateTo(Int32 stepId) in D:devFlexViewTechnicalWebMainlineSrcWebServiceFlowServiceFlow.cs:line 440
at Web.Tests.ServiceFlowFixture.CanNavigateToWithNavigationControllerHandledTest() in D:devFlexViewTechnicalWebMainlineTestsUnit TestsWeb.TestsServiceFlowFixture.cs:line 1439


The test is something like this:

global::Esi.FlexView.PL.Web.ServiceFlow.ServiceFlow target = RecorderManager.CreateMockedObject<global::Esi.FlexView.PL.Web.ServiceFlow.ServiceFlow>(Constructor.Mocked, StrictFlags.AllMethods);

// ...

using (RecordExpectations recorder = RecorderManager.StartRecording())
{
  recorder.DefaultBehavior.CheckArguments();

  target.CanNavigateTo(stepId);
  recorder.CallOriginal();

  accessor.CheckIsNotDisposed();

  recorder.ExpectAndReturn(navigationController.CanNavigateTo(target, stepId, out expected), true);
}

actual = target.CanNavigateTo(stepId); // Line 1439


Adding the expectation for the calls to ToString() solves the problem:

recorder.ExpectAndReturn(target.ToString(), "").RepeatAlways();
answered by paulo.morgado (11k points)
0 votes
Paulo hi,
The verify exception is thrown since somewhere the "ToString" method is being invoked.
please note that you have specified the strict flag causing TypeMock to threw this exception each time an unexpected method is called:

RecorderManager.CreateMockedObject<global::Esi.FlexView.PL.Web.ServiceFlow.ServiceFlow>(Constructor.Mocked, StrictFlags.AllMethods); 

and you also asked the original method to be executed:
recorder.CallOriginal(); 

Most likely somewhere inside "CanNavigateTo" you call the "ToString"

Adding expectation for "ToString" naturally solve the issue.
answered by lior (13.2k points)
0 votes
I just wrote a simple example of this:

public interface IFlow
{
    bool CanNavigate(int i);
}

public interface IController
{
    bool CanNavigate(IFlow flow, int id, out bool can);
}

public class Flow : IFlow
{
    private IController controller;

    public bool CanNavigate(int id)
    {
        bool can;

        if (this.controller.CanNavigate(this, id, out can))
        {
            return can;
        }

        return false;
    }

    public override string ToString()
    {
        return base.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        MockManager.Init();

        using (MockScope scope = new MockScope())
        {
            Flow target = RecorderManager.CreateMockedObject<Flow>(Constructor.Mocked, StrictFlags.AllMethods);

            Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject accessor = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target);

            IController controller = RecorderManager.CreateMockedObject<IController>(Constructor.Mocked, StrictFlags.AllMethods);

            accessor.SetField("controller", controller);

            int id = 10;
            bool can = false;
            using (RecordExpectations recorder = RecorderManager.StartRecording())
            {
                recorder.DefaultBehavior.CheckArguments();

                target.CanNavigate(id);
                recorder.CallOriginal();

                recorder.ExpectAndReturn(controller.CanNavigate(target, id, out can), true);
            }

            Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreEqual(can, target.CanNavigate(id));
        }
    }
}


Unhandled Exception: TypeMock.VerifyException:
TypeMock Verification: Unexpected Call to Flow.ToString()
at TypeMock.MockManager.a(String A_0, String A_1, Object A_2, Object A_3, Boolean A_4, Object[] A_5)
at TypeMock.InternalMockManager.getReturn(Object that, String typeName, String methodName, Object methodParameters, Boolean isInjected, Object p1, Object p2, Object p3)
at MockIController.CanNavigate(IFlow , Int32 , Boolean& )
at Flow.CanNavigate(Int32 id)
at Program.Main(String[] args)


Just comment out the ToString() implementation or record an expectation for 2 calls to ToString().
answered by paulo.morgado (11k points)
0 votes
Paulo hi,

I've checked what you sent and indeed this is a defect.

The ToString() was indeed called, but the call was made from somewhere inside TypeMock code. :twisted:

Thank you for the great reproduce code, it really helped in finding the problem.
I'll update you as soon as a fix will be available.
answered by lior (13.2k points)
...