如何在 RequestScope 中测试 Ninject Factory returns 相同的实例

How to test a Ninject Factory returns the same instance in RequestScope

在 WebApi 应用程序中,我使用 Ninject 注入一个工厂,该工厂允许使用 类 创建一个根据他们的要求确定范围的 DbContext。我希望能够编写一个单元测试来验证对请求范围上下文 return 同一实例的同一工厂的两次调用。

工厂界面为:

public interface IContextFactory
{
    IMyContext GetContext();
    IMyContext GetTransientContext();
}

Ninject 配置如下所示:

 Bind<IContextFactory>().ToFactory();
 Bind<IMyContext>().To<MyContext>()
     .InRequestScope()
     .NamedLikeFactoryMethod((IContextFactory f) => f.GetContext());
 Bind<IMyContext>().To<MyContext>()
     .InTransientScope()
     .NamedLikeFactoryMethod((IContextFactory f) => f.GetTransientContext());

我的单元测试如下:

[Fact]
public void RequestScopedContextAlwaysSame()
{
    // Arrange
    NinjectWebCommon.Start();
    var factory = (IContextFactory)NinjectWebCommon.Bootstrapper.Kernel.GetService(typeof(IContextFactory));

    //Act
    var context1 = factory.GetContext();
    var context2 = factory.GetContext();

    //Assert
    Assert.Same(context1, context2);
}

我预计对工厂的两次调用都会 return 同一个实例,但实际上它们是两个不同的实例。我认为这是应用程序中的测试错误,我已经能够成功验证在调用 GetContext() 方法时将同一实例注入不同的消费者。

我怀疑这在单元测试中不起作用,因为没有 HttpContext 并且 InRequestScope() 依赖它。有办法解决这个问题吗?

I suspect this is not working in a unit test because there is no HttpContext and InRequestScope() depends on it.

我认为你是对的。你可以试试 :

 Bind<IMyContext>().To<MyContext>()
     .InScope(ctx => this.Scope)
     .NamedLikeFactoryMethod((IContextFactory f) => f.GetContext());

其中 this.Scope 是您的测试 class 的 属性 (任何引用类型都可以),其值在您的测试设置时初始化

或者,如果您仍想使用 InRequestScope 语法,您可以尝试:

    public class MyPlugin : INinjectHttpApplicationPlugin
    {
        private Object Scope { get; } = true;

        public void Dispose(){}

        public INinjectSettings Settings { get; set; }

        public object GetRequestScope(IContext context)
        {
            return Scope;
        }

        public void Start() { }

        public void Stop() { }
    }

那么您的测试将类似于:

    public void RequestScopedContextAlwaysSame()
    {
        var kernel = new StandardKernel();
        kernel.Components.Add<INinjectHttpApplicationPlugin, MyPlugin>();
        kernel.Bind<IContextFactory>().ToFactory();
        kernel.Bind<IMyContext>().To<MyContext>()
            .InRequestScope()
            .NamedLikeFactoryMethod((IContextFactory f) => f.GetContext());
        kernel.Bind<IMyContext>().To<MyContext>()
            .InTransientScope()
            .NamedLikeFactoryMethod((IContextFactory f) => f.GetTransientContext());

        var factory = kernel.Get<IContextFactory>();
        //Act
        var context1 = factory.GetContext();
        var context2 = factory.GetContext();

        //Assert
        Assert.IsTrue(context1.Equals(context2));
    }