Search code examples
c#mockingnmock

C# Mock a Class With an Internal Property Setter


I am trying to build a unit test. The class Position is implemented in a third party library. But for my unit test I need the Size property to be set to a specific value.

public class Position
{
    private double _size;

    private double Size
    {
        get
        {
            return _size;
        }

        internal set
        {
            _size = value;
        }
    }
}

I read this post: How do you create a unit-testing stub for an interface containing a read-only member? but could not figure out how to make it work for me.

This is the class under test (just a simplified example). The posargument in the CalcPositionMetric() method must be of type Position:

public class PositionMetrics
{
    public PositionMetrics()
    {}

    public double CalcPositionMetric(Position pos)
    {
        return 2 * pos.Size;
    }
}

Here is a piece of my unit test:

using NUnit.Framework;
using NMock;

[TestFixture]
public class PositionUnitTests
{
    [Test]
    public void TestPosition()
    {
        Mock<Position> tmpPosMock   = mFactory.CreateMock<Position>();
        tmpPosMock.Expects.One.GetProperty(v => v.Size).WillReturn(7); /* !!! Exception !!! System.ArgumentException : mock object position has a getter for property Size, but it is not virtual or abstract */

        /* Execute Test with  tmpPositions*/
        PositionMetrics pm = new PositionMetrics();
        double result      = pm.CalcPositionMetric(tmpPosMock.MockObject)
        Assert.AreEqual(14, result);
    }
}

But as you can see I get an exception. Could somebody help me to resolve this problem? Any other solutions are also welcome!

Cheers Konstantin


Solution

  • New answer for the updated question I suggest you to introduce some kind of a proxy interface for that. See the code below:

    interface IPosition { 
        int Size { get; }
    }
    class Position { //in 3rd party lib
        public int Size {
            get { return 5; }
        }
    }
    class RealPosition : IPosition { //use this as your real object instead of using Position directly
        private Position position;
        public RealPosition(Position position) {
            this.position = position;
        }
        public int Size {
            get { return position.Size; }
        }
    }
    class MockPosition : IPosition { //use this for testing
        public int Size{ get; set; }
    }
    public class Program {
        static void Main(string[] args) {
            var pos = new MockPosition { Size = 7 };
            Console.WriteLine(Calc(pos));    //prints 14
            Console.ReadLine();
        }
        static int Calc(IPosition pos) { //change your method signature to work with interface
            return pos.Size * 2;
        }       
    }
    

    Old answer If the class is not sealed you don't need any mocking libraries. Just use the new modifier for the required properties like this:

    class Position {
        public int Size { get { return 5; } }
    }
    
    class MockPosition : Position {
        public new int Size { get; set; }
    }
    ....
    var mock= new MockPosition();
    mock.Size = 7;
    

    To use these items in some sort of list you'll have to cast them like this:

    var items = new List<Position>();
    for (int i = 0; i < 5; i++) {
          items.Add(new MockPosition { Size = i });
    }
    foreach (var item in items.Cast<MockPosition>()) {
           Console.Write("{0}\t", item.Size); //prints 0 1 2 3 4
    }
    

    If it is sealed and the property is not virtual than you'll have to use some other techniques, Moq (which I guess you are using) does not allow that