2011-06-22 39 views
0

我有一個迭代行爲的接口,並且我在Rhinomocks中嘲笑它。示例界面和類是我的問題的一個非常簡單的版本。嘲諷迭代行爲

每次調用LineReader.Read()時,LineReader.CurrentLine()都會返回一個不同的值 - 下一行。這種行爲我至今還沒有能夠在模擬中重現。因此,它已成爲我不時迴歸的一個小型業餘愛好項目。我希望你能進一步幫助我。

internal class LineReader : ILineReader 
{ 
    private readonly IList<string> _lines; 
    private int _countOfLines; 
    private int _place; 

    public LineReader(IList<string> lines) 
    { 
     _lines = lines; 
     _countOfLines = lines.Count; 
     _place = 0; 
    } 

    public string CurrentLine() 
    { 
     if (_place<_countOfLines) 
     { 
      return _lines[_place]; 
     } 
     else 
     { 
      return null; 
     } 

    } 

    public bool ReadLine() 
    { 
     _place++; 
     return (_place < _countOfLines); 
    } 

} 

編輯不完整的單元測試添加

[Test] 
    public void Test() 
    { 
     IList<string> lineListForMock = new List<string>() 
              { 
               "A", 
               "B", 
               "C" 
              }; 

     MockRepository mockRepository = new MockRepository(); 
     ILineReader lineReader = mockRepository.Stub<ILineReader>(); 

     //Setup the values here 

     mockRepository.ReplayAll(); 

     bool read1 = lineReader.ReadLine(); 
     Assert.That(read1, Is.True); 
     Assert.That(lineReader.CurrentLine(), Is.EqualTo("A")); 

     bool read2 = lineReader.ReadLine(); 
     Assert.That(read2, Is.True); 
     Assert.That(lineReader.CurrentLine(), Is.EqualTo("B")); 

     bool read3 = lineReader.ReadLine(); 
     Assert.That(read3, Is.True); 
     Assert.That(lineReader.CurrentLine(), Is.EqualTo("C")); 

     bool read1 = lineReader.ReadLine(); 
     Assert.That(read1, Is.False); 


    } 
+0

什麼時候開始一些代碼爲你的單元測試? –

+0

@Thomas,給我兩分鐘:o) – Morten

回答

4

這就是你需要:

var enumerator = new List<string> { "A", "B", "C" }.GetEnumerator(); 
var lineReader = MockRepository.GenerateStub<ILineReader>(); 

lineReader.Stub(x => x.CurrentLine()) 
    .Return("ignored") 
    .WhenCalled(x => x.ReturnValue = enumerator.Current); 

lineReader.Stub(x => x.ReadLine()) 
    .Return(false) // will be ignored 
    .WhenCalled(x => x.ReturnValue = enumerator.MoveNext()); 
+0

太棒了...試試吧!謝謝 – Morten

1

我不知道我是否有最新版本的犀牛嘲笑,但我.Return方法沒有考慮委託/動作 - - 對於做你想做的事情可能有用。

但是,你似乎更接近基於狀態的測試這裏,所以也許只是創建用於測試(或存根,假的你自己的模擬實現---你選擇:)

然後,你可以控制的精確你以後的價值觀。

+0

請問使用DynamicMock 改變什麼? – Morten

+0

'Return'方法似乎具有相同的簽名,所以不需要:( –

+0

請參閱我自己的解決方案,但在許多情況下這會非常複雜,通常創建自己的模擬實現會容易得多 - - 正如你所建議的那樣 – Morten

2

這似乎這樣的伎倆:

[TestFixture] 
public sealed class TestIterativeRhinoReturn 
{ 
    private int _count; 
    private int _countOfLines; 
    private IList<string> _lines; 
    private string _currentLine; 
    [SetUp] 
    public void SetUp() 
    { 
     _count = -1; 

     _lines= new List<string>() 
              { 
               "A", 
               "B", 
               "C", 
               null 
              }; 


     _countOfLines = _lines.Count; 
     _currentLine = null; 
    } 


    [Test] 
    public void Test() 
    { 

     MockRepository mockRepository = new MockRepository(); 
     ILineReader lineReader = mockRepository.DynamicMock<ILineReader>(); 

     lineReader.Stub(r => r.ReadLine()).Callback(new ReadLineDelegate(ReadRecord)).Return(_count < _countOfLines); 
     lineReader.Stub(r => r.CurrentLine()).Do(new CurrentStringDelegate(ReturnString)).Return(_currentLine); 

     mockRepository.ReplayAll(); 

     bool read1 = lineReader.ReadLine(); 
     Assert.That(read1, Is.True); 
     Assert.That(lineReader.CurrentLine(), Is.EqualTo("A")); 

     bool read2 = lineReader.ReadLine(); 
     Assert.That(read2, Is.True); 
     Assert.That(lineReader.CurrentLine(), Is.EqualTo("B")); 

     bool read3 = lineReader.ReadLine(); 
     Assert.That(read3, Is.True); 
     Assert.That(lineReader.CurrentLine(), Is.EqualTo("C")); 

     bool read4 = lineReader.ReadLine(); 
     Assert.That(read4, Is.False); 
     Assert.That(lineReader.CurrentLine(), Is.Null); 


    } 


    public delegate bool ReadLineDelegate(); 

    private bool ReadRecord() 
    { 
     _count++; 
     return (_lines[_count]!=null); 
    } 

    public delegate string CurrentStringDelegate(); 

    private string ReturnString() 
    { 
     return _lines[_count]; 
    } 

通知行:

 lineReader.Stub(r => r.ReadLine()).Callback(new ReadLineDelegate(ReadRecord)).Return(_count < _countOfLines); 
     lineReader.Stub(r => r.CurrentLine()).Do(new CurrentStringDelegate(ReturnString)).Return(_currentLine); 

和委託方法ReadRecord()和ReturnString()。現在每個讀取的返回值都會改變。

+0

非常時髦!---需要記住這一點+1 –

+0

是的,你需要模擬這個使用自定義回調函數 - Do和回調函數需要委託,委託函數返回的值是模擬函數在調用時返回的值,更多信息 - http://goo.gl/77xrc Item#7。訪問每個調用中的參數值以確定結果 – Gishu

+0

@Gishu,我很高興終於找到了如何去做,但是這給我留下了一個印象,嘲笑這種行爲將會使用界面的老式手工虛擬實現而不是Rhinomocks十來簡單得多。 – Morten