热门使用 Moq 为 SqlDataReader 编写单元测试用例
Hot to write Unit Test case for SqlDataReader using Moq
我有以下方法,想通过DataReader编写映射结果的单元测试用例。
public interface IIMGAdvancedSearchDBProvider
{
clsGPAdvancedSearchResult GetSearchResult(clsIMGAdvancedImageSearchCriteria searchCriteria);
}
public class clsIMGAdvancedSearchSQLDBProvider : IIMGAdvancedSearchDBProvider
{
public clsGLGJSearchResultItem GetSearchResult(clsIMGAdvancedImageSearchCriteria searchCriteria)
{
using (var sqlConnection = DfxDbConnection)
{
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.Parameters.Add("@userKey", SqlDbType.UniqueIdentifier).Value = State.WebUserKey;
sqlCommand.Parameters.Add("@SiteCode", SqlDbType.VarChar).Value = State.SiteCode;
sqlCommand.Parameters.Add("@MaxRows", SqlDbType.Int).Value = searchCriteria.MaxRows;
//Add required client, client group filter paramters
AddClientAndClientGroupFilterParameters(searchCriteria, sqlCommand);
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = GetCompleteSQLStatement(searchCriteria);
var reader = sqlCommand.ExecuteReader();
return alTransaction(reader);
reader.Close();
}
}
return null;
}
private clsGLGJSearchResultItem GetJournalTransaction(SqlDataReader reader)
{
return new clsGLGJSearchResultItem
{
ClientKey = DfxUtilities.GetGuidValueFromReader(reader, "ClientKey") ?? Guid.Empty,
JournalId = DfxUtilities.GetLongValueFromReader(reader, "JournalID") ?? 0,
AccountingDate = (DateTime)reader["Date"],
JournalSource =
(enumJournalSources)
Enum.Parse(typeof(enumJournalSources), reader["Source"].ToString()),
Description = DfxUtilities.GetStringValueFromReader(reader, "Description"),
DebitAmount = DfxUtilities.GetDecimalValueFromReader(reader, "DebitAmount") ?? 0,
CreditAmount = DfxUtilities.GetDecimalValueFromReader(reader, "CreditAmount") ?? 0,
ClientCode = DfxUtilities.GetStringValueFromReader(reader, "ClientCode"),
ClientName = DfxUtilities.GetStringValueFromReader(reader, "ClientName"),
Images = GetImageItems(reader)
};
}
}
谁能帮我解决这个问题?
我认为您最好将数据抽象层 (DAL) 接口和 classes(如 IIMGAdvancedSearchDBProvider
和 clsIMGAdvancedSearchSQLDBProvider
)视为您 集成测试而不是单元测试。
换句话说,结合数据库模式、触发器、种子测试数据 + 您的 DAL 实现的测试 class(包括对 ExecuteReader
的调用)。 DAL 应该像您一样精简并排除业务逻辑。对于这些集成测试,您通常会 setup/teardown 测试数据库中的数据。您可能还想为这些 DAL 集成测试 class 创建一个公共基础 class 来设置您的测试数据库连接和一些 SQL 日志记录。还可能维护一个单独的测试数据库,其中包含边缘测试用例数据,或者以其他方式在 setup/teardown 中注入此数据。这里没有嘲笑。
然后您可以 单元测试 业务层 class 通过模拟由您的 DAL 接口 return 编辑的值 IIMGAdvancedSearchDBProvider
在 components/classes 中使用 DAL 接口。我经常尝试先完成 DAL 测试,然后捕获 "real production data" 个案例的一些快照,然后 return 从我的模拟 DAL 对象到业务层单元测试。这样可以避免创建错过生产数据中真实数据边缘情况的模拟。
如果您正在使用 NUnit,请考虑使用它们的 TestCase
、Pairwise
和 Combinatorial
属性来为您的业务层对象生成测试用例(而不是模拟它们)。您可能还会发现我的 ShouldBe 包装器库很方便。
顺便说一句...您的 cls
class 前缀命名约定不标准。
我有以下方法,想通过DataReader编写映射结果的单元测试用例。
public interface IIMGAdvancedSearchDBProvider
{
clsGPAdvancedSearchResult GetSearchResult(clsIMGAdvancedImageSearchCriteria searchCriteria);
}
public class clsIMGAdvancedSearchSQLDBProvider : IIMGAdvancedSearchDBProvider
{
public clsGLGJSearchResultItem GetSearchResult(clsIMGAdvancedImageSearchCriteria searchCriteria)
{
using (var sqlConnection = DfxDbConnection)
{
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.Parameters.Add("@userKey", SqlDbType.UniqueIdentifier).Value = State.WebUserKey;
sqlCommand.Parameters.Add("@SiteCode", SqlDbType.VarChar).Value = State.SiteCode;
sqlCommand.Parameters.Add("@MaxRows", SqlDbType.Int).Value = searchCriteria.MaxRows;
//Add required client, client group filter paramters
AddClientAndClientGroupFilterParameters(searchCriteria, sqlCommand);
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = GetCompleteSQLStatement(searchCriteria);
var reader = sqlCommand.ExecuteReader();
return alTransaction(reader);
reader.Close();
}
}
return null;
}
private clsGLGJSearchResultItem GetJournalTransaction(SqlDataReader reader)
{
return new clsGLGJSearchResultItem
{
ClientKey = DfxUtilities.GetGuidValueFromReader(reader, "ClientKey") ?? Guid.Empty,
JournalId = DfxUtilities.GetLongValueFromReader(reader, "JournalID") ?? 0,
AccountingDate = (DateTime)reader["Date"],
JournalSource =
(enumJournalSources)
Enum.Parse(typeof(enumJournalSources), reader["Source"].ToString()),
Description = DfxUtilities.GetStringValueFromReader(reader, "Description"),
DebitAmount = DfxUtilities.GetDecimalValueFromReader(reader, "DebitAmount") ?? 0,
CreditAmount = DfxUtilities.GetDecimalValueFromReader(reader, "CreditAmount") ?? 0,
ClientCode = DfxUtilities.GetStringValueFromReader(reader, "ClientCode"),
ClientName = DfxUtilities.GetStringValueFromReader(reader, "ClientName"),
Images = GetImageItems(reader)
};
}
}
谁能帮我解决这个问题?
我认为您最好将数据抽象层 (DAL) 接口和 classes(如 IIMGAdvancedSearchDBProvider
和 clsIMGAdvancedSearchSQLDBProvider
)视为您 集成测试而不是单元测试。
换句话说,结合数据库模式、触发器、种子测试数据 + 您的 DAL 实现的测试 class(包括对 ExecuteReader
的调用)。 DAL 应该像您一样精简并排除业务逻辑。对于这些集成测试,您通常会 setup/teardown 测试数据库中的数据。您可能还想为这些 DAL 集成测试 class 创建一个公共基础 class 来设置您的测试数据库连接和一些 SQL 日志记录。还可能维护一个单独的测试数据库,其中包含边缘测试用例数据,或者以其他方式在 setup/teardown 中注入此数据。这里没有嘲笑。
然后您可以 单元测试 业务层 class 通过模拟由您的 DAL 接口 return 编辑的值 IIMGAdvancedSearchDBProvider
在 components/classes 中使用 DAL 接口。我经常尝试先完成 DAL 测试,然后捕获 "real production data" 个案例的一些快照,然后 return 从我的模拟 DAL 对象到业务层单元测试。这样可以避免创建错过生产数据中真实数据边缘情况的模拟。
如果您正在使用 NUnit,请考虑使用它们的 TestCase
、Pairwise
和 Combinatorial
属性来为您的业务层对象生成测试用例(而不是模拟它们)。您可能还会发现我的 ShouldBe 包装器库很方便。
顺便说一句...您的 cls
class 前缀命名约定不标准。