我正在尝试使用RhinoMocks模拟IDataReader,但是我很难通过DataRows进行迭代。到目前为止,这是我所做的:

[TestFixture]
public sealed class TestStubbedDataReader
{
    private int currentRowIdx;  //The current position in the datareader
    private bool notAtEnd;      //Return value of the Reader.Read method
    private int countOfRows;    //Count of rows in the dataReader

    private IList<IDataRecord> rows;    //The datarecords that the reader should iterate through


    [Test]
    public void TestDataReader()
    {

        //Mock the reader
        MockRepository mockRepository = new MockRepository();
        IDataReader reader = mockRepository.Stub<IDataReader>();

        //Build a list of IDataRecords to for the datareader with two records.
        //It mocks a simple table with a Int32 Id field and a string Name field.
        rows = new List<IDataRecord>()
                              {
                                  new RowBuilder().WithValues(1, "AAA").Build(),
                                  new RowBuilder().WithValues(1, "BBB").Build()
                              };

        //Initializing variables for iteration
        currentRowIdx = 0;
        notAtEnd = true;
        countOfRows = rows.Count;

        //NOTE: It is probably here I am doing something wrong!!
        //Seting  up results for for reading the fields of the current record.
        SetupResult.For(reader.GetInt32(0)).Return(rows[currentRowIdx].GetInt32(0));
        SetupResult.For(reader.GetString(1)).Return(rows[currentRowIdx].GetString(1));

        //Seting up returnValue for Reader.Read().
        //Call back increases the currentRowIdx or sets notAtEnd flag to False
        SetupResult.For(reader.Read()).Return(notAtEnd).Callback(new CallBackDelegate(MoveToNextRecord));

        mockRepository.ReplayAll();


        Int32 previousId = -1;
        string previousName = string.Empty;

        //Here I iterate through the DataReader.
        while (reader.Read())
        {
            Console.WriteLine("Read ID:  " + reader.GetInt32(0) + " Name: " + reader.GetString(1));
            //dataValueObjects.Add(new ToxDataValueObject(reader));
            Console.WriteLine("Read");

            Assert.That(reader.GetInt32(0), !Is.EqualTo(previousId), "Id is the same as in the previous record");
            Assert.That(reader.GetString(1), !Is.EqualTo(previousName), "Name is the same as in the previous record");

            previousId = reader.GetInt32(0);
            previousName= reader.GetString(1);

        }

    }


    public delegate bool CallBackDelegate();


    private bool MoveToNextRecord()
    {
        if (currentRowIdx<= countOfRows) //Not at the end yet; increas
        {
            currentRowIdx++;
        }
        else                            //At the end. Next time, Reader.Read should return False
        {
            notAtEnd = false;
        }

        return notAtEnd;
    }



}


//Builder for DataRows
internal class RowBuilder
{
    private MockRepository _mockRepository;
    private IDataRecord _dataRecord;

    public RowBuilder()
    {
        //Initialise and create stubbed datarecord.
        _mockRepository = new MockRepository();
        _dataRecord = _mockRepository.Stub<IDataRecord>();
    }

    //Set return values, and return builder
    public RowBuilder WithValues(int id, string name)
    {
        SetupResult.For(_dataRecord.GetInt32(0)).Return(id);
        SetupResult.For(_dataRecord.GetString(1)).Return(name);
        return this;
    }


    //Return the mocked DataRow
    public IDataRecord Build()
    {
        _mockRepository.ReplayAll();
        return _dataRecord;
    }
}


读取器按预期循环两次,但是第二次迭代的返回值与第一次相同。应该做什么???

最佳答案

我的建议:避免模拟具有潜在复杂(和隐藏)行为的组件。而是以不太通用的方式定义适合您需求的适配器接口,并在您的代码中使用它而不是IDataReader。然后模拟该接口,这应该是一个简单得多的任务。

在生产代码中,定义并使用与真正的IDataReader一起使用的适配器接口的实现。

10-06 07:52