C# - 单元测试视图模型的公共获取器而不调用类构造函数?



如何在不调用类的构造函数的情况下从单元测试中调用 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()方法。

PeeledBananasgetter 是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实例化了该类。两者都实现了IDatabaseGetBananas(),因此无论如何monkey都可以工作。

谢谢你的提示,恩科西!

最新更新