我正在尝试使用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
一起使用的适配器接口的实现。