0

我使用 Fluent NHibernate 代码创建 MySQL 数据库 SessionFactory。没有配置文件(配置中的连接字符串只有一个值 - 配置文件的 connectionStrings 部分)。

SessionFactory 创建代码包含在数据层类中:SessionFactoryManager,它实现了一个单例内部 SessionFactory,数据层和业务层使用它通过 SessionFactoryManager.OpenSession() 获取所有会话。

我的一些业务层方法在内部调用 SessionFactoryManager.OpenSession() 以对表示层透明的方式创建会话。因此,当调用此方法时,没有涉及会话的参数或返回值(在使用这些业务层方法时保持表示层“与会话无关”)。

当我为业务层编写集成测试时,我的问题出现了:我想让它们在 SQLite 内存数据库上运行。我创建了一个使用 Fluent 配置来配置 SQLite 数据库的 SessionFactoryManager。

但是在测试那些在内部创建会话的方法时,我不能告诉他们使用我的测试 SessionFactory(配置为使用 SQLite)。所以调用了“真正的”SessionFactory,所以使用的是 MySql 数据库,而不是 SQLite。

我正在考虑几种可能的解决方案,但似乎没有一个是正确的。

我可以将数据层中的 NHibernate 配置迁移到配置文件,并为开发/生产和测试环境制作不同的 NHibernate 配置文件,但我真的更愿意继续使用 Fluent 代码。

我还可以修改我的数据层以使用单个配置值、databaseMode 或类似值,以设置要使用的数据库:测试内存或真实数据库。并编写一些 switch(databaseMode) 语句,例如“case inMemory: { ... fluent code for in-memory SQLite ... } case standard: { ... fluent code for standard database ... }”。我根本不喜欢这种方法,我不想仅仅为了测试目的而修改我的数据层代码功能。

请注意,我不是在测试数据层,而是在测试业务层。对测试 NHibernate 映射、Dao 或类似功能不感兴趣。我已经对此进行了单元测试,可以使用 SQLite 数据库运行。

此外,更改数据库不是我的应用程序的要求,因此我对实现允许我动态更改 DBMS 的重大更改不太感兴趣,我只是为了编写测试才来这个需要。

重要的一点:当使用内存 SQLite 时,所有新会话的数据库连接必须相同,否则数据库对象对新会话不可用。因此,当使用 SessionFactory.OpenSession() 创建新会话时,必须提供参数“连接”。但此参数不应与非内存数据库一起使用。所以 switch(databaseMode) 应该用于任何单个会话的创建!另一个我完全不喜欢的数据层代码更改。

我正在认真考虑放弃并使用真实数据库运行我的测试,或者至少在一个空数据库上运行我的测试,并为任何测试执行创建和删除它的对象。但是有了这个,测试执行肯定会变慢。有任何想法吗?提前致谢。

4

1 回答 1

0

最后我的解决方案是控制反转:我改变了我的数据层,所以我可以注入一个自定义的 SessionFactoryBuilder 类,使 Fluently.Configure(...) 变得神奇。

在我的数据层中,我使用“真正的”MySqlSessionFactoryBuilder,在我的测试项目中,我编写 TestMySqlFactoryBuilder 或 TestSQLiteSessionFactoryBuilder 类,或者我需要的任何东西。

我仍然有 SQLite 功能的问题,它要求所有会话都使用相同的连接,并且必须在每个 ISession.Open() 调用中作为参数传递。到目前为止,我还没有修改我的数据层来添加该功能,但我想在将来这样做。可能通过向我的 SessionFactory 单例添加一个静态私有成员来存储用于创建 SchemaExport 的连接,以及一个静态私有布尔成员(如 PreserveConnection)来声明此连接必须存储在该私有成员中并在每个 ISession.Open() 中使用。并且还要包装 ISession.Open() 并确保没有直接打开任何会话。

于 2013-06-11T17:40:24.493 回答