Dependency injection 如何使用MOQ对象测试Ninject构造函数参数?

Dependency injection 如何使用MOQ对象测试Ninject构造函数参数?,dependency-injection,tdd,moq,ninject,Dependency Injection,Tdd,Moq,Ninject,我最近一直在做我的第一个测试驱动开发项目,并且一直在学习Ninject和MOQ。这是我第一次尝试这一切。我发现TDD方法发人深省,Ninject和MOQ都很棒。我正在从事的项目并不特别适合Ninject,因为它是一个高度可配置的C#程序,旨在测试web服务接口的使用 我已经将它分解成模块,在整个车间都有接口,但我仍然发现,在从Ninject内核获得服务的实现时,我必须使用大量构造函数参数。比如, 在我的Ninject模块中 Bind<IDirEnum>().To<DirEnum

我最近一直在做我的第一个测试驱动开发项目,并且一直在学习Ninject和MOQ。这是我第一次尝试这一切。我发现TDD方法发人深省,Ninject和MOQ都很棒。我正在从事的项目并不特别适合Ninject,因为它是一个高度可配置的C#程序,旨在测试web服务接口的使用

我已经将它分解成模块,在整个车间都有接口,但我仍然发现,在从Ninject内核获得服务的实现时,我必须使用大量构造函数参数。比如,

在我的Ninject模块中

Bind<IDirEnum>().To<DirEnum>()
在我的Configurator类中(这是主要入口点),它将所有服务连接在一起

class Configurator
{

    public ConfigureServices(string[] args)
    {
        ArgParser argParser = new ArgParser(args);
        IDirEnum dirEnum = kernel.Get<IDirEnum>(
            new ConstructorArgument("filePath", argParser.filePath),
            new ConstructorArgument("fileFilter", argParser.fileFilter),
            new ConstructorArgument("includeSubDirs", argParser.subDirs)
        );
类配置器
{
公共配置服务(字符串[]args)
{
ArgParser ArgParser=新的ArgParser(args);
IDirEnum dirEnum=kernel.Get(
新的构造函数参数(“filePath”,argParser.filePath),
新的构造函数参数(“fileFilter”,argParser.fileFilter),
新的构造函数参数(“includeSubDirs”,argParser.subDirs)
);
filePath、fileFilter和includeSubDirs是程序的命令行选项。到目前为止还不错。但是,作为一个有责任心的人,我有一个涵盖这段代码的测试。我想使用MOQ对象。我已经为我的测试创建了一个Ninject模块

public class TestNinjectModule : NinjectModule
{
    internal IDirEnum mockDirEnum {set;get};
    Bind<IDirEnum>().ToConstant(mockDirEnum);
}
公共类TestNinjectModule:NinjectModule
{
内部IDirEnum mockDirEnum{set;get};
Bind().ToConstant(mockDirEnum);
}
在我的测试中,我这样使用它

[TestMethod]
public void Test()
{
    // Arrange
    TestNinjectModule testmodule = new TestNinjectModule();
    Mock<IDirEnum> mockDirEnum = new Mock<IDirEnum>();
    testModule.mockDirEnum = mockDirEnum;
    // Act
    Configurator configurator = new Configurator();
    configurator.ConfigureServices();
    // Assert

    here lies my problem! How do I test what values were passed to the
    constructor arguments???
[TestMethod]
公开无效测试()
{
//安排
TestNinjectModule testmodule=新的TestNinjectModule();
Mock mockDirEnum=new Mock();
testModule.mockDirEnum=mockDirEnum;
//表演
Configurator Configurator=新的Configurator();
configurator.ConfigureServices();
//断言
这就是我的问题!我如何测试传递给
构造函数参数???
因此,上面显示了我的问题。我如何测试传递给模拟对象的ConstructorArguments的参数呢?我猜Ninject在这种情况下会放弃ConstructorArguments,因为绑定不需要它们。我可以用MOQ对象来测试吗?还是需要手工编写一个实现DirEnum并接受nd‘记录’构造函数参数

n、 b.此代码是“示例”代码,即我没有逐字复制我的代码,但我认为我已经表达了足够的内容,希望能够传达问题?如果您需要更多上下文,请询问

谢谢你的关注。温柔点,这是我第一次;-)


Jim

您设计应用程序的方式存在一些问题。首先,您直接从代码中调用Ninject内核。这被称为and。这使得测试应用程序变得更加困难,并且您已经体验到了这一点。您试图在单元测试中模拟Ninject容器,这会导致使事情变得非常复杂

接下来,您将在
DirEnum
类型的构造函数中注入基元类型(
string
bool

以“编译时”依赖项为例 通过构造函数参数和 通过方法的“运行时”依赖关系 参数

我很难猜测这个类应该做什么,但是由于您将这些在运行时发生变化的变量注入
DirEnum
构造函数,因此最终会得到一个难以测试的应用程序

有多种方法可以解决这个问题。想到的两种方法是使用方法注入和使用工厂。哪种方法可行取决于您

使用方法注入,您的
配置程序
类将如下所示:

类配置器
{
私有只读IDirEnum目录;
//通过构造器注入氘
公共配置程序(IDirEnum dirEnum)
{
this.dirEnum=dirEnum;
}
公共配置服务(字符串[]args)
{
var parser=新的ArgParser(args);
//将参数注入到方法中
this.dirEnum.SomeOperation(
argParser.filePath
argParser.fileFilter
argParser.subDirs);
}
}
使用工厂时,您需要定义一个知道如何创建新的
IDirEnum
类型的工厂:

接口IDirEnumFactory
{
IDirEnum CreateDirEnum(字符串文件路径、字符串文件过滤器、,
bool包括subdirs);
}
您的
配置
类现在可以依赖于
IDirEnumFactory
接口:

类配置器
{
私有只读IDirEnumFactory dirFactory;
//通过构造函数注入工厂
公共配置程序(IDirEnumFactory dirFactory)
{
this.dirFactory=dirFactory;
}
公共配置服务(字符串[]args)
{
var parser=新的ArgParser(args);
//使用工厂创建新的IDirEnum
var dirEnum=this.dirFactory.CreateDirEnum(
parser.filePath
parser.fileFilter
语法分析器;
}
}
请参阅这两个示例中的依赖项是如何注入到
Configurator
类中的。这称为,与服务定位器模式相反,
Configurator
通过调用Ninject内核来请求其依赖项

现在,由于您的
Configurator
完全不受任何IoC容器的限制,您现在可以通过注入它所期望的依赖项的模拟版本,轻松地测试这个类

剩下的就是在应用程序的顶部配置Ninject容器(用DI术语:the)。对于方法注入示例,容器配置与fac保持不变
[TestMethod]
public void Test()
{
    // Arrange
    TestNinjectModule testmodule = new TestNinjectModule();
    Mock<IDirEnum> mockDirEnum = new Mock<IDirEnum>();
    testModule.mockDirEnum = mockDirEnum;
    // Act
    Configurator configurator = new Configurator();
    configurator.ConfigureServices();
    // Assert

    here lies my problem! How do I test what values were passed to the
    constructor arguments???