1

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

出厂界面为:

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);
}

我希望对工厂的两个调用都返回相同的实例,但实际上它们是两个不同的实例。我认为这是应用程序中的一个测试错误,我已经能够成功验证同一个实例在调用该GetContext()方法时被注入到不同的消费者中。

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

4

1 回答 1

1

我怀疑这在单元测试中不起作用,因为没有 HttpContext 并且 InRequestScope() 依赖于它。

我想你是对的。您可以尝试:

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

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

或者,如果您仍想使用 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));
    }
于 2019-08-12T17:46:04.367 回答