在测试用例中为InstancePerApiRequest生成一个会话

本文关键字:一个 会话 测试用例 InstancePerApiRequest | 更新日期: 2023-09-27 17:51:02

我有两个控制器的测试用例。我想确保每个测试用例都接收一个唯一的会话实例,以便模拟InstancePerWebApiRequest。我目前的实现是有缺陷的,因为它在多个测试用例中使用单个session实例。但是,如果我在一个测试用例之后处理了Scope,那么即使我已经从Autofac重新请求了一个新的Session,我也会被告知Session已经关闭。

这是我得到的:

public class AutofacRegistrations
{
    public static void RegisterAndSetResolver()
    {
        var containerBuilder = new ContainerBuilder();
        containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        //  Per Design Patterns: Elements of Reusable Object-Oriented Software - an abstract factory is often used as a singleton.
        containerBuilder.Register(x => new NHibernateConfiguration().Configure().BuildSessionFactory()).SingleInstance();
        containerBuilder.RegisterType<NHibernateDaoFactory>().As<IDaoFactory>().SingleInstance();
        containerBuilder.RegisterType<StreamusManagerFactory>().As<IManagerFactory>().SingleInstance();
        //  Everything else wants an instance of Session per API request, so indicate that:
        containerBuilder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerApiRequest();
        containerBuilder.Register(x => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).InstancePerApiRequest();
        ILifetimeScope container = containerBuilder.Build();
        var dependencyResolver = new AutofacWebApiDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
    }
}

这里我将工厂声明为单例,并指出我希望每个api请求都有一个session。

下面是我如何设置我的测试:

public abstract class StreamusTest
{
    protected ILog Logger;
    protected IDaoFactory DaoFactory;
    protected IManagerFactory ManagerFactory;
    protected Helpers Helpers;
    protected ISession Session;
    private IDependencyScope Scope;
    [TestFixtureSetUp]
    public void TestFixtureSetUp()
    {
        StreamusWebApi.InitializeApplication();
        //  TODO: I feel like this is incorrect because Session is only generated once. Shouldn't it be SessionPerTestCase? 
        Scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope();
        Logger = (ILog)Scope.GetService(typeof(ILog));
        DaoFactory = (IDaoFactory)Scope.GetService(typeof(IDaoFactory));
        ManagerFactory = (IManagerFactory)Scope.GetService(typeof(IManagerFactory));
        Session = (ISession)Scope.GetService(typeof(ISession));
        Helpers = new Helpers(Logger, Session, ManagerFactory);
    }
    [SetUp]
    public void SetUp()
    {
        //  TODO: I think I want to be generating a Scope per SetUp and dispose of it in TearDown.
        //  Scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope();
        //  Logger = (ILog)Scope.GetService(typeof(ILog));
        //  Session = (ISession)Scope.GetService(typeof(ISession));
    }
    [TearDown]
    public void TearDown()
    {
        //  Scope.Dispose(); 
    }
    [TestFixtureTearDown]
    public void TestFixtureTearDown()
    {
        Scope.Dispose(); 
    }
}

我觉得这是不正确的,因为我只实例化我的范围一次在TestFixtureSetup。如果我在每个测试用例之后(在TearDown中)处理我的作用域,那么我的第二个测试用例抛出一个异常,指示会话已关闭。

我认为我当前的实现在我所有的测试用例中使用了一个会话,这是不正确的。有人能就如何正确设置这个提供一些建议吗?

以下是我的实际测试用例,供参考:

[TestFixture]
public class ClientErrorControllerTest : StreamusTest
{
    private ClientErrorController ClientErrorController;
    [SetUp]
    public new void TestFixtureSetUp()
    {
        ClientErrorController = new ClientErrorController(Logger, Session, ManagerFactory);
    }
    [Test]
    public void CreateError_ShortMessage_ErrorCreated()
    {
        var clientErrorDto = new ClientErrorDto
            {
                Message = "Hello World",
                ClientVersion = "0.99",
                LineNumber = 2
            };
        ClientErrorDto createdErrorDto = ClientErrorController.Create(clientErrorDto);
        Assert.NotNull(createdErrorDto);
    }
    [Test]
    public void CreateError_LongMessage_MessageTruncatedErrorCreated()
    {
        var clientErrorDto = new ClientErrorDto
            {
                Message =
                    "Hello World This is a Really Long Message Which is going to be over 255 characters in length when finished which will cause the end result message to be truncated with three periods as to not overflow the database. Can I confirm that this is happening? Thanks",
                ClientVersion = "0.99",
                LineNumber = 2
            };
        ClientErrorDto createdErrorDto = ClientErrorController.Create(clientErrorDto);
        Assert.NotNull(createdErrorDto);
        Assert.That(createdErrorDto.Message.Length == 255);
    }
}

在测试用例中为InstancePerApiRequest生成一个会话

这似乎与您关于获取每个请求范围的其他问题有些相似/相关。这里的答案与之前相同- 您需要使用HttpRequestMessage来管理生命周期范围。这意味着也要从生命周期范围中解析控制器,进而解析注册为InstancePerApiRequest的所有依赖项。

另外,正如在前面的回答中提到的,我真的会避免设置全局静态变量(全局依赖解析器)。当您设置静态时,您可能会把测试环境搞得一团糟,并且很难重现问题或间歇性故障。