Property and constructor mocking questions

5 posts, 0 answers
  1. Bob
    Bob avatar
    20 posts
    Member since:
    Mar 2012

    Posted 21 Mar 2012 Link to this post

    Hi.

    I'm performing an evaluation of JustMock and running through some simple cases. I'm finding the manual a bit light on examples and quickly running into cases which fail for reasons which I can't find explained anywhere.

        class Fake1
        {
            public Fake1(int a) { Prop1 = a; }
            public int Prop1 { get; set; }
        }
     
        [Test]
        public void Test1()
        {
            Fake1 f = Mock.Create<Fake1>(7);
    //      Mock.ArrangeSet(() => f.Prop1 = Arg.AnyInt).CallOriginal(); // FAILS
            Mock.Arrange(() => f.Prop1).CallOriginal();
            f.Prop1 = 5;
            int a = f.Prop1;
            Assert.AreEqual(5, a);
        }
     
        [Test]
        public void Test2()
        {
    //      Fake1 f = Mock.Create<Fake1>(7); // FAILS
            Fake1 f = Mock.Create<Fake1>(Constructor.Mocked);
            int intercepted = 0;
            Mock.ArrangeSet(() => f.Prop1 = Arg.AnyInt).DoInstead((int x) => intercepted = x);
            f.Prop1 = 5;
            Assert.AreEqual(5, intercepted);
        }

    How come in Test1 I have to arrange the property get but not the property set? It isn't a problem, just rather unintuitive and I don't see anywhere where this behaviour is explained. If I uncomment the commented out line it fails with:

    Test 'M:Library1.Tests.Test3' failed: There were some problems intercepting the mock call. Optionally, please make sure that you have turned on JustMock's profiler while mocking concrete members.
        Telerik.JustMock.MockException: There were some problems intercepting the mock call. Optionally, please make sure that you have turned on JustMock's profiler while mocking concrete members.
        at Telerik.JustMock.Expectations.Expectation.ThrowForInvalidCall(IInvocation invocation)
        at Telerik.JustMock.Expectations.Expectation.Process(IInvocation invocation)
        at Telerik.JustMock.Mock.ArrangeSet(Action action)
        Class1.cs(84,0): at Library1.Tests.Test3()

    Why does Test2 fail if I don't mock the constructor? This might be a problem for me. This test is just noddy code but in real code one of my most desirable use cases is to be able to construct an object with various arguments and then mock some of its properties/methods while other properties/methods call the original implementation. If I uncomment the commented out line it fails with the same error as Test1.

    I'm using JustMock 2012 SP1, assembly version 2012.1.229.0, 60 day trial version

    Thanks.
  2. Bob
    Bob avatar
    20 posts
    Member since:
    Mar 2012

    Posted 22 Mar 2012 Link to this post

    After reading the manual more carefully I've noticed that my syntax for the Create method is wrong and that it should be:

    Fake1 f = Mock.Create<Fake1>(() => new Fake1(7), Behavior.Strict);

    However even after making that modification it still fails in the exact same way for both tests.

    What's more after enabling Behaviour.Strict Test1 should throw a MockException on the property set which is not arranged due to the commented out line of code, but it doesn't and just dies with the same message as before.
  3. DevCraft R3 2016 release webinar banner
  4. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 23 Mar 2012 Link to this post

    Hi Bob,

    Thanks again for bringing up the questions. Here I have modified the first test in the following way:
    [TestMethod]
    public void Test1()
    {
        Fake1 f = Mock.Create<Fake1>(Constructor.Mocked);
     
        f.Prop1 = 5;
     
        int a = f.Prop1;
     
        Assert.AreEqual(5, a);
    }

    The auto arrange feature of JustMock is used here which is that you dont have to do Mock.Arrange for setting and getting a property value on mocked object.

    Moving forward, i wrote the second test in this way:
    Fake1 f = Mock.Create<Fake1>(Constructor.Mocked);
     
    int intercepted = 0;
     
    Mock.ArrangeSet(() => f.Prop1 = Arg.AnyInt).DoInstead((int x) => intercepted = x);
     
    f.Prop1 = 5;
     
    Assert.AreEqual(5, intercepted);

    However, the following test should pass as well even if you write it in the following way:

    Fake1 f = Mock.Create<Fake1>(7);
     
    int intercepted = 0;
     
    Mock.ArrangeSet(() => f.Prop1 = Arg.AnyInt).DoInstead((int x) => intercepted = x);
     
    f.Prop1 = 5;
     
    Assert.AreEqual(5, intercepted);


    Here it is failing because you are setting the property in constructor that is raising the OnJITCompilationStarted event as it is a non-virtual property. Therefore, Mock.ArrangeSet is failing to intercept it. However, I noticed that since you are doing it in Mock.Create therefore it should not be the case and I have created a task for it in the PITS which you can further follow here:


    http://www.telerik.com/support/pits.aspx#/public/justmock/10429


    Kind Regards,
    Mehfuz
    the Telerik team
    Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
  5. Bob
    Bob avatar
    20 posts
    Member since:
    Mar 2012

    Posted 23 Mar 2012 Link to this post

    Thanks Mehfuz, I'll certainly keep a close eye on the progress of that issue.

    As I mentioned it's an important use case for me to be able to mock parts of objects which have been constructed using their own constructors, so I'm trying to understand in which cases this works and in which cases it doesn't.

    Consider this:

    class Fake4
    {
        public Fake4(int a) { Method1(a); }
        public int Method1(int a) { return m_internal = a; }
        private int m_internal;
    }
     
    ...
     
    [Test]
    public void Test9()
    {
        Fake4 f = Mock.Create<Fake4>(7);
        int intercepted = 0;
        Mock.Arrange(() => f.Method1(Arg.AnyInt)).DoInstead((int a) => intercepted = a);
        f.Method1(5);
        Assert.AreEqual(5, intercepted);
    }
    This fails with the error:

    Test 'M:Library1.Tests.Test9' failed:   Expected: 5
      But was:  0

        NUnit.Framework.AssertionException:   Expected: 5
          But was:  0
        
        at NUnit.Framework.Assert.That(Object actual, IResolveConstraint expression, String message, Object[] args)
        at NUnit.Framework.Assert.AreEqual(Int32 expected, Int32 actual)
        Class1.cs(172,0): at Library1.Tests.Test9()

    0 passed, 1 failed, 0 skipped, took 0.50 seconds (Ad hoc).

    But if I create the Mock using Mock.Create<Fake4>(Constructor.Mocked) instead, it works, interestingly it also works if I recode the object like this:
    class Fake4
    {
        public Fake4(int a) { m_internal = a; }
        public int Method1(int a) { return m_internal = a; }
        private int m_internal;
    }
    So I'm getting the impression that constructing an object using its own constructor works, but only as long as the constructor does not use any of the properties/methods that are also going to be mocked. Is this correct?

    If so then that creates one minor issue, which is that if the only constructors which will work are those which do not use any of the properties/methods that will also be used by the Mock, then in the majority of cases there will be little point using the object's constructor at all, and the only recourse will be to arrange all the property/method calls directly.

    If that's the way it is, then I can probably live with that, but I would like it to be clear what will work and what won't.
  6. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 28 Mar 2012 Link to this post

    Hi Bob,

    Thanks again for bringing up the question. Since you are mocking a non-virtual method that involves a profiler, you can include an initialization block for the method that is invoked inside constructor.

    For the above case, the initialization block looks like:

    static UnitTest1()
    {
        Mock.Partial<Fake4>().For<int, int>((x, i) => x.Method1(i));
    }

    Once I included it, the test worked as expected. As with the second example; you are setting the field m_internal directly therefore it is not affecting the mocking of Method1 anyway.

    Hope you had your questions answered.

    Kind Regards,
    Mehfuz
    the Telerik team

    Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
Back to Top
DevCraft R3 2016 release webinar banner