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

Setting private member variable

7 Answers 743 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Jiti
Top achievements
Rank 1
Jiti asked on 22 Oct 2012, 09:47 PM
What is the just mock equivalent of setting the value of a private member variable?

public class foo
{
private IEventAggregator _ea;
...
}

I just want to do something like this:

foo mockedFoo = Mock.Create<foo>();
IEventAggregator fakeEA = Mock.Create<IEventAggregator>();
Mock.NonPublic.Arrange(foo, "_ea", fakeEA);

But this is not working for me and gives me an error:
System.ArgumentException: Could not resolve the target method; make sure that you have provided arguments correctly.

7 Answers, 1 is accepted

Sort by
0
Kaloyan
Telerik team
answered on 23 Oct 2012, 02:05 PM
Hi Jiti,

 Thank you for contacting Telerik support.

 In order to fake the returning value of a non-public property/member, you will have to arrange against it`s "get" function.

 Let`s assume we have the following class with it`s private members:
 
public interface IEventAggregator
{
    string firstProp { get; set; }
    int secondProp { get; set; }
}
 
public class Foo
{
    private IEventAggregator myInterfaceWithSet { get; set; }
    private string myStringWithGet { get; set; }
 
    public string ReturningMyInterface()
    {
        return myInterfaceWithSet.firstProp;
    }
 
    public string ReturningMyString()
    {
        return myStringWithGet;
    }
}

 There are couple of examples that I have prepared about your issue:

  1. We will fake the string property:
    [TestMethod]
    public void ShouldReturnFakeStringWithGetFunction()
    {
        var mockedFoo = Mock.Create<Foo>(Behavior.CallOriginal);
     
        string expected = "telerik";
     
        //arrange
        Mock.NonPublic.Arrange<string>(mockedFoo, "myStringWithGet").Returns(expected);
     
        //act
        string actual = mockedFoo.ReturningMyString();
     
        //assert
        Assert.AreEqual(expected, actual);
    }
    You can see that we are arranging that our property is returning a certain value when called.

  2. Faking an interface private member is almost the same. The only difference here is that we need to create a mocked instance of our class/interface with the wanted parameters:
    [TestMethod]
    public void ShouldMockPrivatePropertyWithGetFunction()
    {
        var mockedFoo = Mock.Create<Foo>(Behavior.CallOriginal);
        var mockedIEA = Mock.Create<IEventAggregator>();
     
        mockedIEA.firstProp = "telerik";
        mockedIEA.secondProp = 55;
     
        //arrange
        Mock.NonPublic.Arrange<IEventAggregator>(mockedFoo, "myInterfaceWithSet").Returns(mockedIEA);
     
        //act
        string actual = mockedFoo.ReturningMyInterface();
     
        //assert
        Assert.AreEqual("telerik", actual);
    }

 I hope this solves your issue. If I can help you with anything else, please do not hesitate to ask.

Regards,
Kaloyan
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Jiti
Top achievements
Rank 1
answered on 23 Oct 2012, 05:31 PM
Thank you for your reply.
It does work when there is a property or function that sets the member variable. But my production code does not need a setter, it gets set in the constructor. Writing a setter just so that the member variable can be mocked did not seem right. That was why I was wondering if it was possible to set the value of the member variable directly.

For e.g. if I do this,

var realFoo = new foo();
PrivateObject po = new PrivateObject(realFoo);
po.SetField("_ea", fakeEA);   // This works (But I need to used a mocked version of foo so in that case po.SetField does not work)

Is there something similar to the above SetField method in JustMock or is it only possible if there is a setter or a method that sets its value, like in the solution proposed?

Thanks,
Jiti
0
Jiti
Top achievements
Rank 1
answered on 23 Oct 2012, 09:35 PM
I just checked and looks like just having a private setter does not work. It needs to be a private method that takes an argument.

So if the production code had the property
private IEventAggregator EventAggregator { get; set; }
then in the test case,
Mock.NonPublic.Arrange(foo, "EventAggregator", fakeEA);
does not work!

But if the production code had the method
private void SetEventAggregator(IEventAggregator ea)
{
_ea = ea;
}
then in the test case,
Mock.NonPublic.Arrange(foo, "SetEventAggregator", fakeEA);
works!

I wonder why it does not work with private property.

Thanks,
Jiti

0
Kaloyan
Telerik team
answered on 24 Oct 2012, 03:22 PM
Hi Jiti,

 Thank you for coming back to us.

 As I can understand from your first reply, you are trying to fake datum. Unfortunately this is not possible in JustMock, neither in other mocking tools. What our product is expected to do is to fake an object by mocking its behavior.

 For example: You create a fake class, so that you can comfortably arrange the new behavior of its functionality, or methods.

 However, as I noted above, mocking or faking datum is not directly allowed. Nevertheless, there are ways and principles in programming that can permit you, fake the value of a certain variable. One of them, I would recommend, is the using of a property, that is acting directly with your private member variable. Having such, you can easily mock its get or set function, so that it returns or takes a certain data. 
 
 Let`s assume you are having this "SomeClass" class. 
class SomeClass
{
    public SomeClass()
    {
        _myProperty = 123;
    }
 
    public int _myProperty;
 
    public int MyProperty
    {
        get { return this._myProperty; }
        set { this._myProperty = value; }
    }
}
As you can see there is a member variable "_myProperty", that is taking its value inside the constructor. The mandatory here is that, we have a property "MyProperty", that can show or change the variable`s value. From now on, it is good to use 'MyProperty', instead of "_myProperty", to cover the rest of "SomeClass" functional logic. If we continue to the testing part, you will notice that, now it is very easy to fake the whole behavior of our class:
[TestMethod]
public void TestMethod1()
{
    var mock = Mock.Create<SomeClass>();
 
    // Arrange
    Mock.Arrange(() => mock.MyProperty).Returns(321);
 
    // Act
    var actualValue = mock.MyProperty;
    var origValue = mock._myProperty;
 
    // Assert
    Assert.AreNotEqual(actualValue, origValue);
    Assert.AreEqual(321, actualValue);
    Assert.AreEqual(123, origValue);
}

 As for your second concern, I must say that you are right. Having a private setter won`t let you fake the returning value. You will need a private property with both get and set functions, or atleast with a getter, so that you can arrange that function to return the desired value, the same way, as you are arranging methods for example:
Mock.NonPublic.Arrange<IEventAggregator>(foo, "EventAggregator").Returns(fakeEA);
 Note that, you will need to specify the property type ("<IEventAggregator>") first. Then you have to point the previously mocked class/interface ("foo") with its property/method you would like to arrange against ("EventAggregator"). Finally you need to fake its get function, so that it returns your "fakeEA", instead of the original value (".Returns(fakeEA)").

 I hope you will find this information useful and it will lead you to solving you issue. Please, let me know if I can be helpful with anything else.

Regards,
Kaloyan
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Chuck
Top achievements
Rank 1
answered on 01 Feb 2013, 09:26 PM
I'd like to follow up on this, which seems to me a major failing (inability to mock a private member variable). Consider the following

public class TM
{
    private Task m_ActiveTask = null;
    // provide readonly access to the world
    public Task ActiveTask
    {
        get { return m_ActiveTask;}
    }
    // let users set the Active task, which is a complicated operation, NOT just an assignment to internal variable
    public void SetActiveTask (string sTaskName)
    {
        // lots of complicated manipulations, including
        Task oNewTask = new Task(...);
        //finally resulting in
        m_ActiveTask = oNewTask;
    }
    // later, another function may need to test whether any task is active
    public void Cleanup()
    {
        if(null != m_ActiveTask)
        {
            // do some cleanup, then
            m_ActiveTask = null;
        }
    }
}

Now, I want to write a unit test for Cleanup. Obviously, I need to put a Mocked Task object in m_ActiveTask. But it is a private member variable.
Obviously, I do not want to expose it as public. I have good and sound reasons for maintaining within TM the ability to SET the variable, and not to allow the casual caller to mess with it.
How does one proceed in this situation?
Let's assume JustMock JustWon't allow me to set the member variable directly (see how I JustMade that little joke? :), and that I'm willing to refactor my code so that class methods always access via the property, thus:

    public void Cleanup()
{
     if(null != ActiveTask) // use property
     {
         // do some cleanup, then
         m_ActiveTask = null;
     }
}

If I then define my property THIS way, is there some way to get it JustRight?

public Task ActiveTask
{
    get { return m_ActiveTask; }
    private set { m_ActiveTask = value; } // make setter private to the class
}

Thanks.
(btw, Jiti, is a co-worked of mine, and we are working on different parts of the same product)
0
Chuck
Top achievements
Rank 1
answered on 01 Feb 2013, 09:46 PM
Nevermind.
If I'm willing to refactor to use the property in the TM class, of course I can sufficiently mock a .Returns on the property.
I still believe the ability to set private member variables will be sine qua non for comprehensive test coverage. There will be times when the state of private member variables that are PURELY private, and need NO exposure, will determine code path execution. Requiring the programmer to make them private *properties* rather than member variables is just silly.
0
Kaloyan
Telerik team
answered on 05 Feb 2013, 04:13 PM
Hello Chuck,

Thank you for the detailed feedback.

You are correct that such feature will definitely enrich JustMock. 

I would suggest you using our Ideas and Feedback portal, so that other clients could also vote for its implementation in our product. 

Kind regards,
Kaloyan
the Telerik team
Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
Tags
General Discussions
Asked by
Jiti
Top achievements
Rank 1
Answers by
Kaloyan
Telerik team
Jiti
Top achievements
Rank 1
Chuck
Top achievements
Rank 1
Share this question
or