我尝试单元测试的类之一使用了OleDbConnection对象。此对象负责根据传递的 SQL 字符串返回 MS Access 文件中保存的信息。代码为:
public void getInformation(DateTime start, DateTime finish)
{
string getInfo = "";
string query = "//Query for MS Access goes here";
transactions = addTransactions(query, conn);
}
其中 addTransactions 是一个私有方法,它返回从数据库中检索到的列表:
private List<string> addTransactions(string query, OleDbConnection conn)
{
List<string> returnedData = new List<string>();
OleDbCommand cmd = new OleDbCommand(query, conn);
try
{
if (conn.State == ConnectionState.Closed) conn.Open();
OleDbDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
if (!reader.IsDBNull(0))
}
returnedData.Add(reader.GetString(0));
}
catch (Exception ex)
{
Console.WriteLine("OLEB: {0}", ex.Message);
}
conn.Close();
return returnedData;
}
现在我已经从查看此方法中知道单元测试将很困难,因为公共 getInformation() 方法是无效的。我能做的是测试返回的数据中是否有内容。我的问题是我如何编写涉及 OleDbConnection 的单元测试?
我想到的唯一 2 个潜在解决方案涉及创建一个临时访问文件(不理想,因为我们现在超出了单元测试的范围,再加上在其他开发人员的机器上运行测试时可能会失败)或为 OleDbConnection 创建一个包装器并在单元测试中使用它(这听起来像是最好的方法, 但我不知道从哪里开始)。
或为 OleDbConnection 创建一个包装器并在单元测试中使用它
这就是我的做法。 不能直接模拟/测试的对象通常表示其本身的依赖关系。 并且应该提供所有依赖项,而不是内部实例化。
包装器可以是提供相同功能的简单直通。 让它由接口和该接口的代码驱动,以便您可以为该接口提供模拟以进行单元测试。 (作为额外的奖励,即使正在测试的方法返回void
,您的模拟也会让您观察一些东西。 因此,您不必太深入地钻研正在测试的系统,只需观察模拟中调用的内容即可。
从你模拟的内容的聚合根开始,你需要包装OleDbConnection
。 一个简单的入门示例可能如下所示:
public interface IDbConnection
{
IDbCommand CreateCommand();
// other methods
}
public class MyOleDbConnection : IDbConnection
{
private OleDbConnection conn;
public MyOleDbConnection()
{
// initialize "conn" here
}
public IDbCommand CreateCommand()
{
return conn.CreateCommand();
}
// other pass-thru methods
}
从本质上讲,它只是一个传递包装器,用于底层对象公开的相同功能。 这样做的好处是这个对象实际上不需要进行单元测试,因为它不包含任何有意义的可测试逻辑。 (当然,达到 100% 会很好,但这个级别的投资回报率并不存在。
如您所见,这也涉及以类似的方式为OleDbCommand
创建包装器。 同样,只是直通方法。
一旦你的依赖项被包装和可模拟,你就可以更改你的类来使用包装器。 例如,代替这个:
OleDbCommand cmd = new OleDbCommand(query, conn);
它在内部包含对依赖项的引用,您将执行以下操作:
IDbCommand cmd = conn.CreateCommand();
它要求依赖项引用某物。 这将维护依赖项的责任放在依赖项本身上,而不是在你尝试测试的这个类中。 (并且,在这样做时,试图保持对依赖项的自由。
从类中完全删除依赖项后,您可以自由地模拟和测试您喜欢的所有内容。
只需创建一个 MS 文件并放入包中,然后始终使用相同的文件进行测试,这样您甚至可以写入数据并确切地知道它返回的内容,而不是假设如果返回任何数据是正确的!只是一个想法,有多种方法可以做到。