繁体   English   中英

我如何对 ExecuteReader() 的内部方法进行单元测试

[英]How do i unit test ExecuteReader()'s internal method

我有以下公共的 GetDocuments() 方法,我想对私有的 ReadData() 方法进行单元测试。 我正在使用 Moq 框架。 我必须采取什么方法来使用 GetDocuments() 公共方法测试 ReadData()。

public IEnumerable<DocContent> GetDocuments(){
    sql = "testing"
    return sqlCommand.ExecuteReader<List<DocContent>>(sql, null, 
         (reader) => {
         while (reader.Read()) {
             contentDataList.Add(ReadData(reader));
         }
         return contentDataList;
    });
}


private DocContent ReadData(IDataReader reader) {
    return new DocContent() {
        Key = (string)reader["key"],
        Type = (string)reader["type"],
        ValueAsXmlDoc = ToXmlDocument((string)reader["value"])
    };
}

您正在错误地对该逻辑进行单元测试 - 公共方法签名是IEnumerable<DocContent> GetDocuments - 这就是应该测试的内容。 单元测试不涉及测试被测类的特定内部 只有公共表面。

在您的实例中,听起来您正在做的是测试 sql 对翻译逻辑的响应 - 实际上您可以完全在集成测试中做到这一点。

  1. 您可以使用 SQL Server 语法构建一个 MDF 文件,它是一个内存数据库功能。 您可以轻松地从 Visual Studio 添加项菜单中添加一项。

  2. 您可以使用 Visual Studio 中的 SQL 编辑器在该 MDF 文件中填充全部内容。

  3. 在单元测试时,将SqlConnectionSqlCommand设置为使用内存中的 MDF 文件。 连接字符串是这样的:

    Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={DatabasePath};Database={databaseName};Integrated Security=True;MultipleActiveResultSets=True;Connection Timeout={ConnectionTimeout}

  4. 然后,您可以调用您的公共方法签名并接收通过整个方法链运行的完全水合对象,测试您收到的DocContent对象。 它全面测试您的代码、SQL 驱动程序、您需要执行的 SQL 命令以及返回的对象的转换之间的集成。

您可以这样做的一种方法是将ReadData方法移动到实际的DocContent类并将其公开(或使用构造函数) - 或者拥有一个具有公共ReadData方法的单独类DocContentFactory ,然后进行单元测试并使用它。

在同事的帮助下,我能够测试我的方法。 以下是我为测试我的实现所做的代码更改。 首先,我必须模拟我的 DataReader。 然后在 callback() 的帮助下,我能够触发我的内部私有方法。

    [TestMethod]
    public void GetDocumentsShouldGetDocumentRecordsFromDB() {
        //Arrange
        var keys = new string[] {
            "Valid",
            "Invalid",
        };
        var types = new string[] {
            "Bookmarks",
            "Bookmarks",
        };
        var xmls = new string[] {
            "<Document><Regions></Regions></Document>",
            "<Document><Regions></Regions></Document",
        };

        var readerMock = CreateReaderMock(keys, types, xmls);

        string sqlCommand = null;
        IEnumerable<SqlParameter> sqlParameters = null;
        List<DocContent> docContents = null;

        sqlCommandMock
            .Setup(
                x => x.ExecuteReader(
                    It.IsAny<string>(),
                    It.IsAny<IEnumerable<SqlParameter>>(),
                    It.IsAny<Func<IDataReader, List<DocContent>>>()
                )
            )
            .Callback<string, IEnumerable<SqlParameter>,
            Func<IDataReader, List<DocContent>>>(
                (sql, parameters, readerFunction) => {
                    sqlCommand = sql;
                    sqlParameters = parameters;
                    docContents = readerFunction(readerMock.Object);
                }
            )
            .Returns(() => docContents);

        //Act
        var resultSharedDocContents = migrationDataAccess
            .GetDocuments();

        // Assert SQL command.
        // Verify Statements
    }

private Mock<IDataReader> CreateReaderMock(string[] keys,
            string[] types,
            string[] xmls) {
            var readerIndex = -1;

            var readerMock = new Mock<IDataReader>();
            readerMock
                .Setup(r => r.Read())
                .Returns(() => readerIndex < xmls.Length - 1)
                .Callback(() => readerIndex++);

            readerMock
                .Setup(r => r["key"])
                .Returns(() => keys[readerIndex]);

            readerMock
                .Setup(r => r["type"])
                .Returns(() => types[readerIndex]);

            readerMock
                .Setup(r => r["value"])
                .Returns(() => xmls[readerIndex]);

            return readerMock;
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM