我有一个系统,它在获取消息后 - 将其排队(写入表),另一个进程轮询数据库并将其出列以进行处理。在我的自动测试中,我在同一个过程中合并了操作,但不能(概念上)合并两个操作中的NH会话。
自然 - 出现问题。
我已经阅读了关于让SQLite-InMemory-NHibernate组合在测试环境中工作的一切,但由于“没有这样的表”错误,我现在遇到了RANDOMLY失败的测试。为了说清楚 - “随机”意味着具有相同确切配置和代码的相同测试有时会失败。
我有以下SQLite配置:
return SQLiteConfiguration
.Standard
.ConnectionString(x => x.Is("Data Source=:memory:; Version=3; New=True; Pooling=True; Max Pool Size=1;"))
.Raw(NHibernate.Cfg.Environment.ReleaseConnections, "on_close");
在测试开始时(每次测试),我都会获取“静态”会话提供程序,并请它刷新现有的数据库清理,然后重新创建模式:
public void PurgeDatabaseOrCreateNew()
{
using (var session = GetNewSession())
using (var tx = session.BeginTransaction())
{
PurgeDatabaseOrCreateNew(session);
tx.Commit();
}
}
private void PurgeDatabaseOrCreateNew(ISession session)
{
//http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx
new SchemaExport(_Configuration)
.Execute(false, true, false, session.Connection, null);
}
所以是的,它在不同的会话上,但连接是在SQLite上汇集的,所以我创建的下一个会话将看到生成的模式。然而,虽然大多数时候它都有效 - 但有时后来的“入队”操作会失败,因为它无法看到我传入消息的表格。 此外 - 每个测试套件运行似乎最多发生一次或两次;不是所有的测试都失败了,只是第一个(有时是另一个。不太确定它是否是第二个)。
最糟糕的部分是随机性,自然而然。我告诉自己我现在已经修好了几次,只是因为它只是“停止了失败”。随意。
这发生在FW4.0,System.Data.SQLite x86版本,Win7 64b和2008R2(总共三台不同的机器),NH2.1.2,配置了FNH,在TestDriven.NET 32b进程和NUnit控制台32b进程上。
帮助?
答案 0 :(得分:8)
嗨,我很确定我和你有完全相同的问题。我按照集成测试打开和关闭多个会话。在深入研究SQLite连接池和我自己的一些实验后,我得出以下结论:
SQLite池代码使用WeakReferences缓存连接,WeakReferences对于缓存来说不是最好的option,因为当没有正常(强)引用时,将清除对连接的引用。连接和GC运行。由于无法预测GC的运行时间,因此可以解释“随机性”。尝试在关闭和打开另一个会话之间添加GC.Collect();
,您的测试将始终失败。
我的解决方案是在开放会话之间自己缓存连接,如下所示:
public class BaseIntegrationTest
{
private static ISessionFactory _sessionFactory;
private static Configuration _configuration;
private static SchemaExport _schemaExport;
// I cache the whole session because I don't want it and the
// underlying connection to get closed.
// The "Connection" property of the ISession is what we actually want.
// Using the NHibernate SQLite Driver to get the connection would probably
// work too.
private static ISession _keepConnectionAlive;
static BaseIntegrationTest()
{
_configuration = new Configuration();
_configuration.Configure();
_configuration.AddAssembly(typeof(Product).Assembly);
_sessionFactory = _configuration.BuildSessionFactory();
_schemaExport = new SchemaExport(_configuration);
_keepConnectionAlive = _sessionFactory.OpenSession();
}
[SetUp]
protected void RecreateDB()
{
_schemaExport.Execute(false, true, false, _keepConnectionAlive.Connection, null);
}
protected ISession OpenSession()
{
return _sessionFactory.OpenSession(_keepConnectionAlive.Connection);
}
}
我的每个集成测试都继承自此类,并调用OpenSession()来获取会话。由于[SetUp]属性,每次测试之前Nadit都会调用RecreateDB。
我希望这可以帮助您或其他任何收到此错误的人。
答案 1 :(得分:0)
只有在考试之后你会随机离开会话才会想到的事情。在打开另一个ISession之前,您必须确保已关闭任何现有ISession。如果您没有使用using()语句或手动调用Dispose(),则会话可能仍然存在,从而导致这些随机异常。