我在工厂扩展中广泛使用ninject。我还使用moq来帮助测试,在某些情况下(我的MVVM WPF应用程序中特别复杂的视图模型)我使用ninject模拟内核,以便更容易自动为被测试类所需的资源创建模拟。
在我的常规产品代码中,ninject工厂扩展可以很容易地为工厂声明一个如下所示的界面:
public interface IMyViewModelFactory
{
MyViewModel CreateMyViewModel(int recordNum);
}
并且工厂扩展将自动提供一个实现,该实现将创建方法映射到类的构造函数,同时解析来自ninject的构造函数参数的任何其他依赖项。所以如果我的类有一个看起来像这样的构造函数:
public MyViewModel(ILogger logger, int recordNum)
{
_logger = logger;
_recordNum = recordNum;
}
然后工厂扩展将创建一个工厂方法实现,它从ninject内核获取ILogger并通过我的显式参数。
这一切都适用于常规产品代码,但是尽管我可以告诉我在使用模拟内核时无法在单元测试中使用这种东西。
通常使用模拟内核,我在测试类的初始化方法中设置它,将少量接口绑定到我想测试的具体类,然后让mocking内核自动为其他所有内容提供模拟。然后可以根据特定测试的需要配置这些模拟,除工厂方法外,一切都很好。我发现自己在我的模拟的setup语句中手动实现了工厂方法,如下所示:
Kernel.GetMock<IMyViewModelFactory>()
.Setup(f => f.CreateMyViewModel(It.IsAny<ILogger>(), It.IsAny<int>()))
.Returns((ILogger logger, int recordNum) =>
new MyViewModel(Kernel.Get<ILogger>, recordNum);
那样如果我的测试需要与工厂交互(或者更可能是我正在测试的某个类需要使用工厂来创建一些子视图模型)那么它实际上可以创建实例并且依赖来自模拟内核因此可以根据需要设置为模拟。
大多数时候我喜欢ninject和这些扩展,但这是一个单元测试设置变得非常繁琐的地方。我可能甚至不介意,因为工厂扩展程序在我的产品代码中使用它变得多么容易,我无法弄清楚如何在我的测试中获得相同的好处。当然上面的例子是设计的,遗憾的是在我的许多视图模型中,依赖关系和实际参数的数量很大(我必须设置这种东西的视图模型的数量很大),所以单调乏味变成了更大的交易。
我希望有人可以告诉我,我只是错过了一些明显的东西,并且有一种简单的方法来设置它。
谢谢, 丹尼