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

时间:2019-06-13 22:07:58

标签: c# unit-testing properties nunit

如何在不调用类的构造函数的情况下从单元测试中调用C#属性的公共获取器?

我目前正在为视图模型编写单元测试。

我不是在测试私有方法,而只是在测试公共方法。
我正在测试实现自定义逻辑或验证的所有公共获取器和设置器。

我的课程包含一个私人的项目列表。
我的课程包含一个属性,该属性根据项目的属性值返回其中一些项目。
我的课程包含一个构造函数,该构造函数调用数据库。

我想测试此getter是否正确返回了这些项目,因为getter是该类的公共接口的一部分,应该对其进行测试。

我的问题是我想以某种方式模拟我的类,以便可以在单元测试期间调用class属性的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属性的吸气剂。
我不想调用构造函数,因为我不想调用GetBananasFromDatabase()方法。

PeeledBananas获取器是monkey类的公共API的一部分,因此应该对其进行单元测试。但是在测试过程中不应调用数据库。

我可以创建一个新的monkey模拟,无论如何我都可以调用构造函数,并且仅模拟GetBananasFromDatabase()方法的行为,但是我不能模拟GetBananasFromDatabase()方法,因为它是私人的。

什么是解决此问题的好方法?

1 个答案:

答案 0 :(得分:1)

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可以从bananas中获得database来获取给定上下文,monkey类不再与特定的{{1 }}实施。

当我想在生产代码中使用IDatabase类时,我用一些monkey实例化该类。当我想对RealDatabase类进行单元测试时,我用一些monkey实例化该类。两者都实现FakeDatabaseIDatabase,因此GetBananas()无论如何都可以工作。

感谢小费,恩科西!