如何模拟IDataReader来测试将SqlDataReader转换为System.DataView的方法

Hri*_*sto 6 c# unit-testing moq mocking idatareader

我是Moq的新手,我正在努力编写单元测试来测试转换SqlDataAdapter为的方法System.DataView.这是我的方法:

private DataView ResolveDataReader(IDataReader dataReader)
{
    DataTable table = new DataTable();

    for (int count = 0; count < dataReader.FieldCount; count++)
    {
        DataColumn col = new DataColumn(dataReader.GetName(count), 
                                        dataReader.GetFieldType(count));
        table.Columns.Add(col);
    }

    while (dataReader.Read())
    {
        DataRow dr = table.NewRow();
        for (int i = 0; i < dataReader.FieldCount; i++)
        {
            dr[i] = dataReader.GetValue(dataReader.GetOrdinal(dataReader.GetName(i)));
        }
        table.Rows.Add(dr);
    }

    return table.DefaultView;
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试创建以创建类似于:

var dataReaderMock = new Mock<IDataReader>();
var records = new Mock<IDataRecord>();
dataReaderMock.Setup(x => x.FieldCount).Returns(2);
dataReaderMock.Setup(x => x.Read()).Returns(() => records);
Run Code Online (Sandbox Code Playgroud)

我想传递一些数据并验证它是否已转换.

谢谢.

Nik*_*nte 9

你和你的嘲笑dataReaderMock.Setup(x => x.Read()).Returns(() => records);一起走在正确的轨道上,但是你出错的地方就是.Read返回一个bool,而不是记录本身,这些都是IDataReader你的方法读出来的.


安排嘲笑:

var dataReader = new Mock<IDataReader>();
dataReader.Setup(m => m.FieldCount).Returns(2); // the number of columns in the faked data

dataReader.Setup(m => m.GetName(0)).Returns("First"); // the first column name
dataReader.Setup(m => m.GetName(1)).Returns("Second"); // the second column name

dataReader.Setup(m => m.GetFieldType(0)).Returns(typeof(string)); // the data type of the first column
dataReader.Setup(m => m.GetFieldType(1)).Returns(typeof(string)); // the data type of the second column
Run Code Online (Sandbox Code Playgroud)

您可以安排列来品尝更多真实数据,类型等.在您的系统中,只需确保第一次计数,GetNames数和GetFieldTypes 数同步.

要安排.Read(),我们可以使用SetupSequence:

dataReader.SetupSequence(m => m.Read())
    .Returns(true) // Read the first row
    .Returns(true) // Read the second row
    .Returns(false); // Done reading
Run Code Online (Sandbox Code Playgroud)

要在测试中使用它,您可以将其提取到方法中:

private const string Column1 = "First";
private const string Column2 = "Second";
private const string ExpectedValue1 = "Value1";
private const string ExpectedValue2 = "Value1";

private static Mock<IDataReader> CreateDataReader()
{
    var dataReader = new Mock<IDataReader>();

    dataReader.Setup(m => m.FieldCount).Returns(2);
    dataReader.Setup(m => m.GetName(0)).Returns(Column1);
    dataReader.Setup(m => m.GetName(1)).Returns(Column2);

    dataReader.Setup(m => m.GetFieldType(0)).Returns(typeof(string));
    dataReader.Setup(m => m.GetFieldType(1)).Returns(typeof(string));

    dataReader.Setup(m => m.GetOrdinal("First")).Returns(0);
    dataReader.Setup(m => m.GetValue(0)).Returns(ExpectedValue1);
    dataReader.Setup(m => m.GetValue(1)).Returns(ExpectedValue2);

    dataReader.SetupSequence(m => m.Read())
        .Returns(true)
        .Returns(true)
        .Returns(false);
    return dataReader;
}
Run Code Online (Sandbox Code Playgroud)

(或者,你可以安排这个Setup,如果这对你的测试类更有意义 - 在这种情况下,dataReadermock将是一个字段,而不是返回值)

示例测试.然后它可以像:

[Test]
public void ResovleDataReader_RowCount()
{
    var dataReader = CreateDateReader();
    var view = ResolveDataReader(dataReader.Object);
    Assert.AreEqual(2, view.Count);
}

[Test]
public void ResolveDataReader_NamesColumn1()
{
    var dataReader = CreateDataReader();
    var view = ResolveDataReader(dataReader.Object);
    Assert.AreEqual(Column1, view.Table.Columns[0].ColumnName);
}

[Test]
public void ResolveDataReader_PopulatesColumn1()
{
    var dataReader = CreateDataReader();
    var view = ResolveDataReader(dataReader.Object);
    Assert.AreEqual(ExpectedValue1, view.Table.Rows[0][0]);
}

// Etc..
Run Code Online (Sandbox Code Playgroud)

(我使用过NUnit,但它与测试方法的不同属性和不同的断言语法类似,对于不同的测试框架)


顺便说一句,我得到了上述改变工作ResolveDataReaderinternal和设置InternalsVisibleTo,但我假设你有一个网关到这个私有方法,因为你已经为你想测试它确实远了.