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

Using Mock.Arrage with PrivateAccessor

5 Answers 95 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Jon
Top achievements
Rank 1
Jon asked on 07 Apr 2017, 09:15 PM

I have not used JustMock in the past year or so but I used to use it to do future mocking of objects that are created in the code.  But now I cannot find any examples of this in my own code or online, so I am not sure how to do this. But I have done it before so I know it is possible.  So I'm hoping someone can point me in the right direction here.

The code below shows what I am doing.  I setup a mock of my class that I am testing, but as a PrivateAccessor so I can use that as needed.  So I grab the instance as my sut. There there, when I run into code that creates another object and does not pass that object in using DI, I thought that you were able to mock that with a .Returns() so that it returns a fake version of whatever object you typically return. However, I cannot get the context to work with the arrange object and I cannot figure out what I need to do.  I did try adding the arrange to the sut, but I could not figure out the syntax.

The first two lines... the mock and sut work fine.  Then the next two lines also work fine, the Mock.Arrage and my test below it to get LoanData.  But now when my sut runs and does things and encounters code such as var something = new LoanData() it is not using the arrange, but the actual code.

So what am I missing?  How can I get that Mock.Arrange to apply to the code from within the Sut?  I can do Sut.Array() but I cannot figure out the syntax. 

Any suggtions are appreciated.  I'm sure it is just a syntax issue and I don't see how to set it up.

public PricingBase()
{
           var mock = new PrivateAccessor(new Classes.PricingEngine.Refactor.PricingEngine(new PricingEngineService()));
           Sut = (Classes.PricingEngine.Refactor.PricingEngine)mock.Instance;
            
           Mock.Arrange(() => new LoanData()).IgnoreArguments().Returns(CreateFakeLoanData());
           var test = new LoanData();
       }

 

 

5 Answers, 1 is accepted

Sort by
0
Kamen Ivanov
Telerik team
answered on 13 Apr 2017, 08:27 AM
Hello Jon,

I apologize for the late response. 

Here is the documentation which addresses the future mocking functionality:
http://www.telerik.com/help/justmock/advanced-usage-future-mocking.html

The code snippet that you have send to us looks fine and I'm confused that it is not working as expected.
I have prepared a sample console application which does mock the same logic as you do so you would be able to find if there are any differences with your code.

Regards,
Kamen Ivanov
Telerik by Progress
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Jon
Top achievements
Rank 1
answered on 14 Apr 2017, 04:33 PM

You misunderstood what I was trying explain with the sample code. What I was showing you there with the [var test] is what worked, but I need it to work through the Sut object. It seems that the Mock.Arrange applies to the local scope and not to anything within the Sut object. I need to be able to mock objects created in the SUT logic... if possible. I thought this was what future-mocking was for. I am pretty sure I have done this before, but I am not sure.

Here's an example that I think is a good example to show you what I am doing.

 

using System;
using Telerik.JustMock;
 
namespace FutureMocking
{
    class Program
    {
        static void Main(string[] args)
        {
 
            var mock = new PrivateAccessor(new PricingEngine());       
            var sut = (PricingEngine)mock.Instance;
 
            Mock.Arrange(() => new LoanData()).Returns(FakeMethod());   // This will not work, I don't think, becuase it is under a different test-context from mock and sut above. Right or wrong?
            //sut.Arrange(() => new LoanData()).Returns(FakeMethod());  // It would seem that you'd have to do something like this... but I don't know and I cannot resolve the syntax.
 
            var finalPrice = sut.Price();                               // This represents the call out to the class that will create a LoanData object and load its properties.                       
            Console.WriteLine($"${finalPrice}");                        // If the fake worked, it would return $50.00. But it returns $100.00 because the actual code is used.           
        }
 
        private static LoanData FakeMethod()
        {
            var loanData = new LoanData { BasePriceRate = 5 };
            return loanData;
        }
    }
     
    public class PricingEngine
    {
        // This is what I am actually trying to unit test.
        // The dependency is LoanData, so I want to mock it if possible to fake it as needed.
        // I cannot inject LoanData here because it would require weeks of reworking the code.
        public decimal Price()
        {
            var loanData = new LoanData { BasePriceRate = 10 };     // This similates what the pricing engine does, it takes into account hundreds of properties in LoanData to come up with and price.
            return loanData.BasePriceRate*10;                       // To simulate a price, I am just taking the property and mulitplig it by 10. I want to fake this for my unit test so my test it not dependant on LoanData having real data.
        }
    }
 
    public class LoanData
    {
        public int BasePriceRate { get; set; }       
    }
 
}

 

 

0
Kamen Ivanov
Telerik team
answered on 19 Apr 2017, 07:39 AM
Hi Jon,

I'm sorry for the misunderstanding in first place.

I reviewed the code that you have sent and I found out what happens.
The future mocking syntax is fine and it is working as expected but that line of code that "breaks" the things is:
var loanData = new LoanData { BasePriceRate = 10 };
As you probably know that this is a syntax sugar for the following:
1. var loanData = new LoanData();
2. loanData.BasePriceRate = 10;
which results in creating the loanData instance with the fake values, as loanData.BasePriceRate is 5 after line 1 is executed and then it is overwritten it with 10 on line 2.

In this case you could do the following:
Create the fake instance of LoanData and then Mock every get of its properties to always return the values that you want by adding ".IgnoreInstance()" before the "Returns()":
var fakeData = FakeMethod();
Mock.Arrange(() => fakeData.BasePriceRate).IgnoreInstance().Returns(5);
This will always return 5 when the getter of BasePriceRate is called for any instance of LoanData class.
Find the updated solution attached to my post.

I hope that this will help you resolve the issue.

Regards,
Kamen Ivanov
Telerik by Progress
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Jon
Top achievements
Rank 1
answered on 19 Apr 2017, 03:45 PM

Okay. That makes sense. I can mock each property of LoanData. There are 87 total (it is a bad design and they should have used a model class, but I can not refactor it for now) and I can mock the properties individually. Thanks for the explanation there.

So does that mean that future-mocking works via properties, or is that just because in our sample we are using properties?

If it does work through the properties like this, what about making LoanData a property in our example?  Would that then allow JustMock to future-mock the whole LoanData object? As opposed to having to mock every property individually? That is more along the line of what I was thinking, but I could mock each of the 87 properties individually, but in the past I recall mocking the object itself. If so, the difference here is that in our example, LoanData was not a property of the LoanData class... but it could be and actually is in my actual application.

That might be what I am misunderstanding, that it works through properties. I could actually do something like the adjusted sample below. This seems to work the way I am expecting it to.

So if I run into an object that I want to future-mock and that object is a property of my SUT class, then I can mock it.  But if it is not a property of my SUT, then I have to mock the individual properties of the class. I think you end up with the same net result, but two different ways to get there that just depends on what sort of code you run into and how the class objects are being used.

 

using System;
using Telerik.JustMock;
 
namespace FutureMocking
{
    internal class Program
    {
        private static void Main(string[] args)
        {
 
            var mock = new PrivateAccessor(new PricingEngine());
            var sut = (PricingEngine)mock.Instance;
 
            var fakeLoanData = FakeMethod();
            Mock.Arrange(() => new LoanData()).IgnoreInstance().Returns(fakeLoanData);
 
            //LoanData fakeLoanData = FakeMethod();
            //Mock.Arrange(() => fakeLoanData.BasePriceRate).IgnoreInstance().Returns(5);
            //Mock.Arrange(() => fakeLoanData.BasePriceRate).IgnoreInstance().Returns(5);
            //Mock.Arrange(() => fakeLoanData.LoanAmount).IgnoreInstance().Returns(350000);
            //Mock.Arrange(() => fakeData.PropertyState).IgnoreInstance().Returns("CA");
 
            var finalPrice = sut.Price();                              
            Console.WriteLine($"${finalPrice}");                       
        }
 
        private static LoanData FakeMethod()
        {
            var loanData = new LoanData
            {
                BasePriceRate = 0.005M,
                LoanAmount = 250000,
                PropertyState = "TX"
            };
            return loanData;
        }
    }
     
    public class PricingEngine
    {
        public LoanData LoanData { get; set; }
 
        public PricingEngine()
        {
            LoanData = new LoanData
            {
                BasePriceRate = 0.0325M,
                PropertyState = "",
                LoanAmount = 0.00M
            };
        }
 
        public decimal Price()
        {           
            LoanData = new LoanData();
 
            if (LoanData.PropertyState == "TX")
                LoanData.FinalPrice = LoanData.BasePriceRate * LoanData.LoanAmount;
            if (LoanData.PropertyState == "CA")
                LoanData.FinalPrice = LoanData.BasePriceRate * 0.5M * LoanData.LoanAmount;
            return LoanData.FinalPrice;
        }
    }
 
    public class LoanData
    {
        public decimal BasePriceRate { get; set; }
        public decimal LoanAmount { get; set; }
        public string PropertyState { get; set; }
        public decimal FinalPrice { get; set; }
    }
 
}

 

 

 

0
Kamen Ivanov
Telerik team
answered on 24 Apr 2017, 07:16 AM
Hello Jon,

I suggested to use the future mocking for mocking a specific property because of the example we had. In this case the properties were modified after the initial creation of the mocked object and that's why taking this approach looks better to me. If they were not modified then we could future mock the class as you have did it in the code in you last post.

Regarding your question about LoanData being a property of the sut it is totally fine to future mock it and the approach again depends on that if the LoadData properties are being modified later or not.

In case they were not when the sut is created and it initializes its own properties the LoanData will take into consideration the specified mock.

Here is an example of what I'm trying to explain:
  • have LoanData as property of another class - PricingEngine
public class PricingEngine
{
    public PricingEngine()
    {
        this.LoanDataProp = new LoanData();
    }
 
    public LoanData LoanDataProp { get; set; }
 
    public decimal Price()
    {
        var loanData = new LoanData();
        return loanData.BasePriceRate * 10;
    }
}
  • We setup a mock for LoanData constructor (future-mock the whole LoanData object):

...
Mock.Arrange(() => new LoanData()).IgnoreInstance().Returns(fakeLoanData);
...

  • Now when we create an instance of our sut(PricingEngine) it will have the LoanDataProp mocked with the fakeLoanData object

I hope that you will find this information helpful.

Regards,
Kamen Ivanov
Telerik by Progress
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Tags
General Discussions
Asked by
Jon
Top achievements
Rank 1
Answers by
Kamen Ivanov
Telerik team
Jon
Top achievements
Rank 1
Share this question
or