集成测试最佳实践

发布于 2024-08-02 09:08:00 字数 537 浏览 10 评论 0原文

我们的团队有数百个集成测试,这些测试会访问数据库并验证结果。我有两个用于所有集成测试的基类,一个用于仅检索测试,一个用于创建/更新/删除测试。仅检索基类在 TestFixtureSetup 期间重新生成数据库,因此每个测试类仅执行一次。 CUD 基类在每次测试之前重新生成数据库。每个存储库类都有其自己对应的测试类。

正如您可以想象的那样,这整个过程需要相当长的时间(运行时间接近 7-8 分钟,并且增长很快)。将此作为我们 CI (CruiseControl.Net) 的一部分运行不是问题,但在本地运行需要很长时间,并且确实禁止在提交代码之前运行它们。

我的问题是,是否有任何最佳实践可以帮助加快这些类型的集成测试的执行速度?

我无法在内存中执行它们(a la sqlite),因为我们使用了 sqlite 不支持的一些数据库特定功能(计算列等)。

此外,整个团队必须能够执行它们,因此在 SQL Server Express 的本地实例或其他实例上运行它们可能很容易出错,除非这些实例的连接字符串都相同。

您的店里是如何实现这一目标的?什么效果最好?

谢谢!

Our team has hundreds of integration tests that hit a database and verify results. I've got two base classes for all the integration tests, one for retrieve-only tests and one for create/update/delete tests. The retrieve-only base class regenerates the database during the TestFixtureSetup so it only executes once per test class. The CUD base class regenerates the database before each test. Each repository class has its own corresponding test class.

As you can imagine, this whole thing takes quite some time (approaching 7-8 minutes to run and growing quickly). Having this run as part of our CI (CruiseControl.Net) is not a problem, but running locally takes a long time and really prohibits running them before committing code.

My question is are there any best practices to help speed up the execution of these types of integration tests?

I'm unable to execute them in-memory (a la sqlite) because we use some database specific functionality (computed columns, etc.) that aren't supported in sqlite.

Also, the whole team has to be able to execute them, so running them on a local instance of SQL Server Express or something could be error prone unless the connection strings are all the same for those instances.

How are you accomplishing this in your shop and what works well?

Thanks!

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

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

发布评论

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

评论(5

顾忌 2024-08-09 09:08:00

将快速(单元)测试和慢速(集成)测试分开,以便可以单独运行它们。使用测试框架提供的任何方法对测试进行分组/分类。如果测试框架不支持对测试进行分组,请将集成测试移至仅包含集成测试的单独模块中。

快速测试应该只需要几秒钟即可运行所有测试,并且应该具有较高的代码覆盖率。这些类型的测试允许开发人员无情地重构,因为他们可以做一个小的更改并运行所有测试,并且非常有信心更改不会破坏任何内容。

缓慢的测试可能需要很多分钟才能运行,他们将确保各个组件能够正确地协同工作。当开发人员所做的更改可能会破坏由集成测试而不是单元测试测试的内容时,他们应该在提交之前运行这些集成测试。否则,CI 服务器将运行缓慢的测试。

Keep your fast (unit) and slow (integration) tests separate, so that you can run them separately. Use whatever method for grouping/categorizing the tests is provided by your testing framework. If the testing framework does not support grouping the tests, move the integration tests into a separate module that has only integration tests.

The fast tests should take only some seconds to run all of them and should have high code coverage. These kind of tests allow the developers to refactor ruthlessly, because they can do a small change and run all the tests and be very confident that the change did not break anything.

The slow tests can take many minutes to run and they will make sure that the individual components work together right. When the developers do changes that might possibly break something which is tested by the integration tests but not the unit tests, they should run those integration tests before committing. Otherwise, the slow tests are run by the CI server.

牵你的手,一向走下去 2024-08-09 09:08:00

在 NUnit 中,您可以使用属性来装饰您的测试类(或方法),例如:

[Category("Integration")]
public class SomeTestFixture{
    ...
}
[Category("Unit")]
public class SomeOtherTestFixture{
    ...
}

然后您可以在服务器上的构建过程中规定所有类别都运行,并且只要求您的开发人员运行可用测试类别的子集。他们需要运行哪些类别将取决于您比我更了解的事情。但要点是他们能够在单元级别进行测试,并且服务器处理集成测试。

in NUnit you can decorate your test classes (or methods) with an attribute eg:

[Category("Integration")]
public class SomeTestFixture{
    ...
}
[Category("Unit")]
public class SomeOtherTestFixture{
    ...
}

You can then stipulate in the build process on the server that all categories get run and just require that your developers run a subset of the available test categories. What categories they are required to run would depend on things you will understand better than I will. But the gist is that they are able to test at the unit level and the server handles the integration tests.

不念旧人 2024-08-09 09:08:00

我是一名java开发人员,但也处理过类似的问题。我发现运行本地数据库实例效果很好,因为速度很快(无需通过网络发送数据),而且这样您就不会在集成测试数据库上产生争用。

我们用来解决此问题的一般方法是设置构建脚本以从配置文件中读取数据库连接字符串,然后为每个环境设置一个文件。例如,一个文件用于 WORKSTATION,另一个文件用于 CI。然后,您设置构建脚本以根据指定的环境读取配置文件。因此,在开发人员工作站上运行的构建使用 WORKSTATION 配置运行,而在 CI 环境中运行的构建则使用 CI 设置。

如果整个数据库模式可以从单个脚本创建,那么每个开发人员都可以快速设置本地数据库进行测试,这也会有很大帮助。您甚至可以将此概念扩展到下一个级别,并将数据库设置脚本添加到构建过程中,以便可以编写整个数据库设置脚本以跟上数据库架构中的更改。

I'm a java developer but have dealt with a similar problem. I found that running a local database instance works well because of the speed (no data to send over the network) and because this way you don't have contention on your integration test database.

The general approach we use to solving this problem is to set up the build scripts to read the database connection strings from a configuration file, and then set up one file per environment. For example, one file for WORKSTATION, another for CI. Then you set up the build scripts to read the config file based on the specified environment. So builds running on a developer workstation run using the WORKSTATION configuration, and builds running in the CI environment use the CI settings.

It also helps tremendously if the entire database schema can be created from a single script, so each developer can quickly set up a local database for testing. You can even extend this concept to the next level and add the database setup script to the build process, so the entire database setup can be scripted to keep up with changes in the database schema.

幸福丶如此 2024-08-09 09:08:00

作为开发环境的一部分,我们有一个 SQL Server Express 实例,它为每台开发机器运行相同的数据库定义。通过 Windows 身份验证,连接字符串是稳定的 - 字符串中没有用户名/密码。

我们真正想做但还没有做的是看看我们是否可以让我们的系统在 SQL Server Compact Edition,类似于具有 SQL Server 引擎的 SQLite。然后我们可以在内存中运行它们,也可以并行运行它们(使用多个进程)。

We have an SQL Server Express instance with the same DB definition running for every dev machine as part of the dev environment. With Windows authentication the connection strings are stable - no username/password in the string.

What we would really like to do, but haven't yet, is see if we can get our system to run on SQL Server Compact Edition, which is like SQLite with SQL Server's engine. Then we could run them in-memory, and possibly in parallel as well (with multiple processes).

木槿暧夏七纪年 2024-08-09 09:08:00

您是否进行过任何测量(使用计时器或类似工具)来确定测试大部分时间都花在哪里?

如果您已经知道数据库重新创建是他们耗时的原因,那么另一种方法是重新生成数据库一次并使用事务来保留测试之间的状态。每个 CUD 类型测试在设置中启动一个事务并在拆卸中执行回滚。这可以显着减少每次测试的数据库设置所花费的时间,因为事务回滚比完整的数据库重新创建更便宜。

Have you done any measurements (using timers or similar) to determine where the tests spend most of their time?

If you already know that the database recreation is why they're time consuming a different approach would be to regenerate the database once and use transactions to preserve the state between tests. Each CUD-type test starts a transaction in setup and performs a rollback in teardown. This can significantly reduce the time spent on database setup for each test since a transaction rollback is cheaper than a full database recreation.

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