c# - 如何模拟 IDataReader 以测试将 SqlDataReader 转换为 System.DataView 的方法

标签 c# unit-testing mocking moq 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;
}

我正在尝试创建类似这样的东西:

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

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

谢谢。

最佳答案

你的模拟是在正确的轨道上,但是 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

您可以根据需要安排列以模拟更多真实数据、类型等。在您的系统中,只需确保第一个计数、GetName 的数量和GetFieldType 的数量是同步的。

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

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

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

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;
}

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

示例测试。然后它可以像这样使用:

[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..

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


顺便说一句,我通过将 ResolveDataReader 更改为 internal 并设置 InternalsVisibleTo 来实现上述功能,但我假设您有一个网关进入这个私有(private)方法,就像你尝试测试它所做的那样。

关于c# - 如何模拟 IDataReader 以测试将 SqlDataReader 转换为 System.DataView 的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35200882/

相关文章:

javascript - 用 casperjs 伪造 xmlhttprequests

c# - 如何在 JavaScript 中加密字符串并在 C# 中解密该字符串

c# - 支持 RTL\Hebrew 并导出到 OOXML\PDF 的 .NET WinForms 编辑器控件?

python - unittest.mock.patch 一个类实例,并设置方法返回值

unit-testing - VS2012 : Clear the test results in Test Explorer when re-running a test that previously failed

Java:用于测试的模拟外部库

unit-testing - 您如何称呼为从模拟中返回而创建的对象?

c# - 桌面应用程序的推送通知?

c# - 如何在 EF Core 3 中启用日志记录?

java - SpringJUnit4ClassRunner 应该初始化它的上下文多少次?