Rhino Mock, чтобы выполнить возврат доходности - PullRequest
4 голосов
/ 08 февраля 2012

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

У меня проблемы с выводом вызова данныхслой.Поскольку он является поддельным, он никогда не перечисляет значения из возвращаемого значения yield, и поэтому мой метод синтаксического анализа никогда не выполняется.

public class Processor
{
    public IUnityContainer Container { get; set; }

    public void ProcessFile(Stream stream)
    {
        var datamanager = Container.Resolve<IDataManager>();                                            
        var things = Parse(stream);        
        datamanager.Save(things);                                
    }

    IEnumerable<string> Parse(Stream stream)
    {
        var sr = new StreamReader(stream);
        while (!sr.EndOfStream)
        {
            string line = sr.ReadLine();
            // do magic
            yield return line;
        }
    }
}

Я пробовал что-то подобное, что, очевидно, не работает.

[TestMethod]        
[ExpectedException(typeof(ApplicationException))]
public void ProcessFile_InvalidInput_ThrowsException()
{
    var mock = new MockRepository();

    var stream = new MemoryStream();
    var streamWriter = new StreamWriter(stream);                
    streamWriter.WriteLine("\\:fail");
    streamWriter.Flush();
    stream.Position = 0;

    var datamanager = mock.Stub<IDataManager>();                        
    TestContainer.RegisterInstance(datamanager);

    var repos = new ProcessingRepository();
    TestContainer.BuildUp(repos);

    using (mock.Record())
    {                         
        Expect.Call(file.InputStream).Return(stream);                            
        Expect.Call(delegate() { repos.Save(new List<string>()) }).IgnoreArguments();
    }
    using (mock.Playback())
    {
        repos.ProcessFile(stream);
    }
}

1 Ответ

3 голосов
/ 08 февраля 2012

Одним из оптимальных решений было бы поместить материал, который происходит в "// do magic", в отдельный метод, чтобы его можно было тестировать модульно в отдельности - без необходимости вызова изнутри цикла while, который обрабатываетStreamReader.

Проблема, которую вы видите, связана с ленивой оценкой перечисления.Поскольку ни один из вашего тестового кода на самом деле не перечисляет «вещи», конечный автомат, созданный «за сценой» для обработки блока итератора, никогда не обрабатывается.

Вам нужно будет заставить элементыбыть перечисленным, чтобы фактически выполнить логику в методе Parse.Вы можете сделать это, используя метод «WhenCalled» Rhino.Mocks (я показываю синтаксис AAA, так как не помню, как использовать семантику записи / воспроизведения):

ПРИМЕЧАНИЕ. Этонепроверенный код

datamanager.Stub(d => d.Save(null)).IgnoreArguments().WhenCalled(m => int count = ((IEnumerable<string>)m.Arguments[0]).Count());

Что происходит, когда при вызове метода Save в вашей заглушке «WhenCalled» передается параметр (m), который содержит информацию о вызванном методе.Возьмите первый аргумент (вещи), приведите его к IEnumerable<string> и получите его количество.Это заставит оценку перечислимого.

...