2011-06-22 1 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); 
    } 

} 

EDIT тест Неполного блок добавлен:

[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

Я не знаю, если у меня есть последняя версия носорог-издевается, но мой метод не Возвращенный принять делегат/действия - - что-то, что могло быть полезно для того, чтобы делать то, что вы хотите.

Однако, вы, кажется, ближе к государственной основе тестирования здесь, так что, может быть, просто создать свой собственный макет реализацию для тестирования (или заглушкой, или поддельные --- вы выбираете :)

Тогда вы можете контролировать точное значения, которые вы после.

+0

Будет ли использовать DynamicMock что-нибудь изменить? – Morten

+0

Метод 'Return', похоже, имеет такую ​​же подпись, поэтому no :( –

+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 и Callback принимают делегаты. Значение, возвращаемое делегатом, будет значением, возвращаемым макетом при его вызове. Дополнительная информация - http://goo.gl/77xrc Пункт № 7. Вы можете даже доступ к значениям аргументов в каждом вызове для определения результата. – Gishu

+0

@ Гишу, я рад, что, наконец, узнал, как это сделать. Однако это оставляет мне впечатление, что насмехается над этим поведением десять будет намного проще, используя старинную рукотворную фиктивную реализацию интерфейса вместо Rhinomocks. – Morten

Смежные вопросы