如何在不调用类的构造函数的情况下从单元测试中调用 C# 属性的公共 getter?
我目前正在为视图模型编写单元测试。
我不是在测试私有方法,只是在测试公共方法。
我正在测试任何实现自定义逻辑或验证的公共 getter 和 setter。
我的类包含一个私有的项目列表。
我的类包含一个属性,该属性根据项的属性值返回其中一些项。
我的类包含一个构造函数,该构造函数调用数据库。
我想测试这个 getter 是否正确返回这些项目,因为 getter 是类公共接口的一部分,应该进行测试。
我的问题是我想以某种方式模拟我的类,以便我可以在单元测试期间调用类属性的 getter。但是,我不想调用类的构造函数,因为这意味着调用数据库并在测试的预期范围之外执行其他工作。
下面是猴子和香蕉的例子:
public class Monkey {
private List<Banana> bananas;
public Monkey()
{
this.GetBananasFromDatabase()
}
public List<Banana> PeeledBananas {
get {
List<Banana> peeledBananas = new List<Banana>();
foreach(Banana banana in this.bananas)
{
if(banana.IsPeeled)
{
peeledBananas.Add(banana);
}
}
return peeledBananas;
}
}
private GetBananasFromDatabase()
{
this.bananas = Database.GetBananas();
}
}
在此示例中,我想测试PeeledBananas
属性的 getter。
我不想调用构造函数,因为我不想调用GetBananasFromDatabase()
方法。
PeeledBananas
getter 是monkey
类的公共 API 的一部分,因此应该对其进行单元测试。但是在测试期间不应调用数据库。
我可以创建一个新的monkey
模拟,无论如何我都可以调用构造函数并模拟GetBananasFromDatabase()
方法的行为,但我不能模拟GetBananasFromDatabase()
方法,因为它是私有的。
解决这个问题的好方法是什么?
Nkosi的评论提供了一个有用的见解。我的问题是由于使用了具体的数据库类型,我的代码是紧密耦合的。通过练习多态和控制反转 (IOC),我决定将数据库接口传递给我的构造函数并在其上调用方法,而不是在具体数据库上调用方法。
现在,当我想对某些东西进行单元测试时,我可以将一个假数据库对象传递到monkey
构造函数中,而不必接触GetBananasFromDatabase()
方法。
代码现在的样子如下:
public class Monkey {
private List<Banana> bananas;
private IDatabase database;
public Monkey(IDatabase database)
{
this.database = database;
this.GetBananasFromDatabase()
}
public List<Banana> PeeledBananas {
get {
List<Banana> peeledBananas = new List<Banana>();
foreach(Banana banana in this.bananas)
{
if(banana.IsPeeled)
{
peeledBananas.Add(banana);
}
}
return peeledBananas;
}
}
private GetInfoFromDatabase()
{
this.bananas = this.database.GetBananas();
}
}
现在,我的monkey
可以从对给定上下文有意义的任何database
中获取bananas
,并且monkey
类不再与特定的IDatabase
实现紧密耦合。
当我想在生产代码中使用monkey
类时,我用一些RealDatabase
实例化该类。 当我想对monkey
类进行单元测试时,我用一些FakeDatabase
实例化了该类。两者都实现了IDatabase
和GetBananas()
,因此无论如何monkey
都可以工作。
谢谢你的提示,恩科西!