2016-01-25 65 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