针对真实数据库对域服务进行单元测试

发布于 2024-08-04 09:47:02 字数 716 浏览 6 评论 0原文

我想知道其他人可能会采用什么方法来针对数据库测试域服务?我已经拥有一系列模拟存储库,可以在域服务中使用它们来测试域服务本身。这些模拟存储库的构建的一部分是它们构建示例聚合和关联实体,并根据模型中使用的相同业务规则对其进行验证。这还提供了一种很好且简单的方法来检测实体本身的潜在影响点(如果实体的接口发生变化)。

我在对 SQL 支持的存储库进行实时测试时发现的主要问题是数据库一致性。例如,一旦运行测试,“创建”方面就已经运行。再次运行它们显然会导致失败,因为数据库不再是原始的。我正在考虑创建一个仅用于此类测试的镜像数据库。它将是最小的,包含结构、可编程性、约束等。我还将为某些已建立的测试提供最小的数据集。我的想法是,我可以有一个存储过程,在测试运行开始之前,我可以调用该存储过程将数据库重置为具有基础数据的“原始”状态。

虽然在功能初步验证后,这在开发人员计算机上并不那么重要,但我更多地研究了将这些测试作为夜间构建的一部分运行的重要性;这样,在测试失败的情况下,可以推迟构建,以免破坏目标部署环境(特别是在这种情况下,这将是测试团队使用的环境)。

我不一定认为平台很重要,但如果有人有特定于实现的问题,我的环境如下所示:

Windows 7(开发)/Windows Server 2008 R2(服务器) Visual Studio 2008 团队版 (C#) Microsoft SQL Server 2008 Standard(开发/服务器)

我正在使用 Team Build 来运行我的构建,但这很可能不是问题范围的因素。

I was wondering what approaches others might have for testing domain services against a database? I already have a series of mock repositories that I am able to use in the domain services for testing the domain services themselves. Part of the construction of these mock repositories is that they build out sample aggregates and associated entities and validate them against the same business rules that would otherwise be used within the model. This also provides a nice and simple means to detect potential impact points within the entities themselves, in the event that their interfaces change.

The main problem that I see with live testing of my SQL-backed repositories is database consistency. For example, once a test is run the "create" aspects have already been run. Running them again would obviously cause failures, as the database is no longer pristine. I was considering create a mirrored database used just for this type of testing. It would be minimal, containing structure, programmability, constraints, etc. I would also provide a minimal set of data for certain established tests. My line of thinking is that I could have a stored procedure that I could call to reset the database to the "pristine" state with base data before the start of the test run.

While this is not as important on a developer machine after the functionality has been initially verified, I am looking more into the importance of running these tests as part of the nightly build; so that in the event of a test failure, the build could be held back as to not foul the target deployment environment (specifically in this case, it would be the environment that the testing team uses).

I do not necessarily think that the platform matters, but in case anyone has implementation specific concerns, my environment looks like the following:

Windows 7 (Development) / Windows Server 2008 R2 (Server)
Visual Studio 2008 Team Edition (C#)
Microsoft SQL Server 2008 Standard (Development/Server)

I am using Team Build to run my builds, but that is most likely not a factor in the scope of the question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夜深人未静 2024-08-11 09:47:02

例如,一旦运行测试,“创建”方面就已经运行了。再次运行它们显然会导致失败,因为数据库不再是原始的。

也许您可以使单元测试具有事务性。运行测试,回滚它们,数据库保持不变。

Spring 具有事务性单元测试类,可以轻松做到这一点。您只需要一个事务管理器。

For example, once a test is run the "create" aspects have already been run. Running them again would obviously cause failures, as the database is no longer pristine.

Maybe you could make your unit tests transactional. Run your tests, roll them back, and the database is unchanged.

Spring has transactional unit test classes that make this easy to do. You just need a transaction manager.

失而复得 2024-08-11 09:47:02

您可以使用 SQL Server Express (我已经做到了使用 2005,但还没有尝试使用 2008)设置存储为文件的“测试平台”数据库。这些可以签入源代码管理,然后测试帮助器类可以 (a) 将它们复制到临时文件夹,(b) 对它们进行写入,以及 (c) 连接到它们。要恢复原始状态,请删除临时副本并重复 ac。

这是一个巨大的痛苦。如果你能得到通过交易(正如达菲莫建议的那样)我会同意。事务的痛点是嵌套事务和分布式事务 - 请注意代码中的那些问题。

You can use SQL Server Express (I've done it with 2005, but haven't tried with 2008) to set up "test deck" databases that are stored as files. These can be checked in to source control, then test helper classes can (a) copy them to temporary folders, (b) write-enable them, and (c) connect to them. To restore the original state, delete the temporary copy and repeat a-c.

This is a huge pain. If you can get by with transactions (as duffymo suggested) I'd go with that. The pain points with transactions are nested transactions and distributed ones - watch out for those in your code.

青衫负雪 2024-08-11 09:47:02

您可以在测试代码中创建一堆数据工厂,这些数据工厂最初在测试运行启动时运行。然后使用事务回滚方法来保持原始状态。
为了使其更容易,请对所有测试类进行子类化,并将事务访问器和回滚代码放入其中。回滚代码可以设置为在每个测试方法完成时自动运行。

You can create a bunch of data factories in testing code which initially run on startup of your test run. Then use the transaction rollback method to keep it pristine.
To make it easier, subclass all your test classes and put the transaction accessor and rollback code in there. Rollback code can be set to automatically run at the completion of every test method.

梨涡少年 2024-08-11 09:47:02

如果您实际上正在对正在访问数据库的存储库执行单元测试,那么您就没有进行单元测试。这可能是一个有用的测试,但它不是单元测试。这是一个集成测试。如果您想这样做并将其称为集成测试,那就完全没问题了。但是,如果您在存储库中遵循良好的设计原则,那么您无需在单元测试中测试数据库。

很简单,您的存储库单元测试并不是根据存储库的输入来测试数据库中发生的广泛影响;而是测试数据库中发生的广泛影响。它是为了确认存储库的输入会导致使用这样那样的一组值来调用协作者。

您会看到,存储库与其余代码一样,应该遵循单一可存储性原则。基本上,您的存储库具有且只有一种可操作性,即调解域模型 API 与底层数据访问技术层(通常是 ADO.Net,但也可以是实体框架或 L2S 或其他层)的关系。以 ADO.Net 调用为例,您的存储库不应承担作为数据层工厂的责任,而应依赖 ADO.Net 数据接口(特别是 IDbConnection/IDbCommand/IDbParameter)中的协作者ETC)。只需将 IDbConnection 作为构造函数参数,然后就到此为止。这意味着您可以针对接口编写存储库单元测试并提供模拟(或假货或存根或任何您需要的东西),并确认所需的方法按顺序以及预期的输入已完成。去看看我关于这个主题的 MS 博客 -> 链接

希望这可以帮助您在将来的测试和设计中避免犯错误。

顺便说一句:如果您想对数据库进行单元测试,则可以。只需使用 Visual Studio 数据库测试即可。它内置于 INTO vs,自 VS2005 以来就已存在。这不是什么新鲜事。但我需要提醒您,它们需要完全独立的单元测试。

if you are actually executing unit tests for your repository that are hitting a database, YOU ARE NOT DOING UNIT TESTING. It might be a helpful test but it's not a unit test. That's an integration test. If you want to do that and call it a integration test then that is perfectly fine. However, if you are following good design principles in your repositories then you do not need to test the database, EVER, in your unit tests.

Quite simply, your repository unit test is NOT to test what wide effects occur in the database based on the input to the repository; it is to confirm that the input to the repository results in a call to a collaborator with such and such a set of values.

You see, the repository, like the rest of your code, should follow the Single Reposibility Principle. Basically your respoitory has ONE and ONLY ONE reposibility and that is to mediate domain model API concerns to the underlying data access technoloy layer (usually ADO.Net but could be Entity Framework or L2S or whatever). Going with the example of ADO.Net calls, your repository shouldn't take on the responsibilty of being a factory for the data layer and instead should take a dependency on a collaborator from the ADO.Net data interfaces (specifically IDbConnection/IDbCommand/IDbParameter etc). Simply take an IDbConnection as a constructor parameter and call it a day. This means that you can write repository unit tests against the interfaces and supply mocks (or fakes or stubs or whatever you need) and confirm that the required methods, in order, with the expected inputs are made. Go check out my MS blog on this exact topic -> Link

Hopfully this helps you from making a mistake in your test and design in the future.

BTW: If you want to unit test the database you can. Just use Visual Studio Database Tests. Its built INTO vs and has been around since VS2005. This is nothing new. But I need to caution you, they need to be completely SEPERATE unit tests.

仄言 2024-08-11 09:47:02

如果您的代码相当独立于数据库,那么使用内存数据库(例如 SQLite)进行单元测试(而不是集成测试)将为您带来速度和易用性的好处(您的测试设置初始化数据库)。

If your code is fairly database independent, using an in-memory database such as SQLite for unit testing (not integration testing) will give you the benefits of speed and ease (your test setups initialize the db).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文