2016-01-25 39 views
1

我正在尝试构建一个单元测试。 该类位置在第三方库中实施。但是对于我的单元测试,我需要将Size属性设置为特定值。C#使用内部属性设置器模拟一个类

public class Position 
{ 
    private double _size; 

    private double Size 
    { 
     get 
     { 
      return _size; 
     } 

     internal set 
     { 
      _size = value; 
     } 
    } 
} 

我看到这篇文章:How do you create a unit-testing stub for an interface containing a read-only member? 但无法弄清楚如何使它为我工作。

这是被测试的类(只是一个简单的例子)。该pos参数在CalcPositionMetric()方法必须是Position类型:

public class PositionMetrics 
{ 
    public PositionMetrics() 
    {} 

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

这里是我的一块单元测试:

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); 
    } 
} 

但你可以看到我得到一个异常。有人能帮我解决这个问题吗?任何其他解决方案也欢迎!

干杯 康斯坦丁

+0

你有'[汇编:InternalsVisibleTo(“My.Tests.Project”)] '里面有'位置'的装配? – NikolaiDante

+0

@NikolaiDante: 我不知道。位置类在第三方库中。它回答你的问题吗? – Konstantin

+0

是的,谢谢,这使得事情更清楚 – NikolaiDante

回答

1

为更新的问题新的答案,我建议你介绍某种代理接口的。请参见下面的代码:

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; 
    }  
} 

老答案如果该类不是sealed你不需要任何嘲讽库。只需使用new修饰符这样所需的属性:

class Position { 
    public int Size { get { return 5; } } 
} 

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

要在某种列表的使用这些物品,你必须投他们这样的:

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 
} 

如果是密封的,该属性是不是虚拟比你不得不使用其他技术,Moq(我猜你正在使用)不允许

+0

嗨Oleg, 感谢您的答复。但它没有完成这项工作。刚刚尝试过。我的测试以'List '作为参数。当我创建列表时,我执行以下操作: 'tmpPositions.Add(mock);' 当访问列表中的项目时,“Size”值仍为0. – Konstantin

+0

我更新了我的代码,其中列出了示例 –

+0

我刚更新我的问题描述。正如你所看到的,我不能使用'MockPosition'作为'CalcPositionMetric()'方法'期望一个'Position'类型的参数。 我只能使用此解决方案进行测试。但比我需要改变正常使用的代码。这是我想避免的。 – Konstantin