This is a migrated thread and some comments may be shown as answers.

Property and constructor mocking questions

4 Answers 538 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Bob
Top achievements
Rank 1
Bob asked on 21 Mar 2012, 06:22 PM
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.

4 Answers, 1 is accepted

Sort by
0
Bob
Top achievements
Rank 1
answered on 22 Mar 2012, 04:58 PM
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.
0
Ricky
Telerik team
answered on 23 Mar 2012, 05:17 PM
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 >>
0
Bob
Top achievements
Rank 1
answered on 23 Mar 2012, 06:23 PM
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.
0
Ricky
Telerik team
answered on 28 Mar 2012, 09:55 PM
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 >>
Tags
General Discussions
Asked by
Bob
Top achievements
Rank 1
Answers by
Bob
Top achievements
Rank 1
Ricky
Telerik team
Share this question
or