这类似于尝试使用模拟对代码进行单元测试时出现的问题。
一种解决方法是将SqlCommand
代码中的使用替换为实现带有ExecuteReader
方法的接口的对象。然后,您可以更轻松地替换对象,也许使用工厂模式。
所以你会替换这样的代码:
using (SqlCommand command = new SqlCommand(query))
{
command.ExecuteReader();
}
和:
var sqlCommandFactory = new SqlCommandFactory();
using (ISqlCommand command = sqlCommandFactory.CreateSqlCommand(query))
{
command.ExecuteReader();
}
首先定义一个包含您要替换的方法的接口:
public interface ISqlCommand
{
SqlDataReader ExecuteReader();
// further interface methods here...
}
然后创建一个工厂,它使用与构造函数相同的签名SqlCommand
:
internal class SqlCommandFactory
{
bool _useMyClass = true;
public ISqlCommand CreateSqlCommand(string query)
{
if (_useMyClass)
{
return new MySqlCommand(query);
}
else
{
return new SqlCommandWrapper(query);
}
}
}
然后,您在MySqlCommand
课堂上编写替代代码:
public MySqlCommand : ISqlCommand
{
public SqlDataReader ExecuteReader()
{
// your new code here
}
}
由于 .NETSqlCommand
类显然没有实现新ISqlCommand
接口,因此创建一个包装类来执行此操作:
public SqlCommandWrapper : ISqlCommand
{
SqlCommand _sqlCommand;
public SqlCommandWrapper(string query)
{
_sqlCommand = new SqlCommand(query);
}
public SqlDataReader ExecuteReader()
{
_sqlCommand.ExecuteReader();
}
}
一些额外的工作,但这种方法的好处是您可以将实现更改为您想要的任何内容,包括单元测试(通过将模拟工厂传递给您的代码)。
额外的工作应该是一次性的,并根据要求保留名称和原始方法签名。这应该使您的代码看起来更熟悉且更易于理解(与自定义/扩展方法相比),尤其是在您(或您的团队)习惯了这种众所周知的模式后。