在 Rails 测试套件中使用工厂的优点和缺点?

发布于 2024-07-17 07:18:49 字数 400 浏览 7 评论 0原文

我目前正在研究一个庞大的 Rails 测试套件。 我无法透露具体细节,但整个套件(单元/功能/某些集成)的运行时间可以长达 5 分钟。

我们完全依赖于固定装置,并且我们没有像我们应该的那样进行嘲笑和存根。

我们接下来的几个冲刺将完全专注于测试套件,提高覆盖率,编写更好的测试,最重要的是编写更有效的测试。

因此,除了我们的测试中更多的嘲笑和存根之外,我们正在考虑用最有可能的“工厂女孩”替换我们的装置。 我看到很多快乐的人都在做类似的情况,但一直无法找到关于搬到工厂的任何缺点的好资源。 在使用来自各种资源的基准测试时,我看到了一些较慢的基准测试,但找不到明确的答案,这就是为什么工厂很好,这就是为什么你可能不想使用它们。

谁能告诉我为什么或为什么我不应该使用工厂?

谢谢!

I'm currently looking at a hefty Rails test suite. It's nothing I can get into specifics about, but the run time for the entire suite (unit/functional/some integration) can run upward of 5 minutes.

We're completely reliant on fixtures and are we're not mocking and stubbing as much as we should be.

Our next few sprints are going to be completely focused on the test suite, both improving coverage, writing better tests and most importantly writing more efficient tests.

So aside from more mocking and stubbing within our tests, we're considering replacing our fixtures with most likely Factory Girl. I see a lot of happy folks doing similar situations but haven't been able to find a good resource on any minuses of moving to a factory. I have seen some slower benchmarks when using benchmarks from various resources but cannot find a definitive this why factories are good and this is why you might not want to use them.

Can anyone educate me on why or why I shouldn't be using factories?

Thanks!

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

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

发布评论

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

评论(2

尤怨 2024-07-24 07:18:49

奥列格的回答很好,但让我提供一下同时使用这两种方法的人的观点。

一段时间以来,Fixtures 一直是 Rails 社区的替罪羊。 每个人都了解固定装置的缺点,但没有人真正拥护其优点。 根据我的经验,工厂本身很容易变得像固定装置一样难以维护(这实际上取决于模式,但我离题了)。 工厂的真正优势在于选择性地更换基于固定装置的痛苦。 让我们来谈谈一些细节。

第一个问题是性能。 如果您可以在不访问数据库的情况下测试大部分应用程序,那么您将看到显着的加速,但对于大多数应用程序,我认为在不完全访问数据库的情况下进行测试是不明智的。 有时您想测试整个堆栈。 每次您模拟或存根时,您都会对可能包含细微错误的接口做出假设。 因此,假设您需要在相当大比例的测试中访问数据库,事务固定装置(您正在使用事务固定装置,对吗?)很可能比为每个测试实例化整个环境要快得多。

我想说,根据测试套件的大小,您确实需要关注 连续集成可将您的开发提升到一个新的水平。 无论你加快多少速度,开发人员仍然需要等待很长时间。 也许看看自动测试也可以在个人层面上提供帮助。 但最终 CI 将允许您在不牺牲开发人员敏捷性的情况下维持测试纪律。

装置真正发挥作用的地方是功能/集成测试。 我的看法是,装置应该为要测试的应用程序设置一个健康的基本状态。 大多数单元测试实际上并不需要这个。 您可以使用工厂获得非常好的单位覆盖率。 然而,当涉及到功能测试时,任何给定页面都可能会遇到数十个模型。 我不想在每次测试中设置所有这些东西。 当我构建越来越复杂的场景时,我越来越接近重新创建全局数据状态,这正是灯具最初设计的目的。

我持有的一个有争议的信念是,在其他条件相同的情况下,我更喜欢 1 次功能测试而不是 20 次单元测试(使用 Rails 的说法)。 为什么? 因为功能测试证明发送给用户的最终结果是正确的。 单元测试非常适合了解功能的细微差别,但最终,您仍然可能在界面上出现错误,从而破坏整个网站。 功能测试让我有信心进行部署,而无需在浏览器中实际加载页面。 我知道我可以将所有内容存根并测试两个接口并获得相同的覆盖范围,但如果我可以在一个简单的测试中测试整个堆栈,而牺牲一点 CPU,我更愿意这样做。

那么我对于固定装置的最佳实践是什么?

  • 为每个模型设置一些以覆盖最广泛的数据类别
  • 当添加跨越许多模型和控制器的主要新功能时,添加一些新的装置来代表主要状态
  • 避免编辑旧的装置,除了添加/删除字段之外
  • 使用工厂更多更小/更本地化的变体
  • 使用工厂来测试分页或其他只需要少数测试的批量创建

另外,让我推荐 Jay Fields 的博客提供了非常好的实用测试建议。 我最喜欢 Jay 博客的一点是,他总是承认测试是非常针对特定项目的,对一个项目有效的方法不一定适用于另一个项目。 他缺乏教条而注重实用主义。

Oleg's answer is great, but let me offer the perspective of someone who is using both.

Fixtures have sort of been the whipping boy of the Rails community for a while. Everyone understands the drawbacks of fixtures, but no one is really championing their strengths. In my experience, factories by themselves can easily become just as difficult to maintain as fixtures (it really depends on the schema, but I digress). The real strength of factories is in selective replacement of fixture-based pain. Let's talk about a couple specifics.

The first issue is performance. If you can test most of your app without hitting the database then you will see a significant speed up, but for most applications I don't think it's wise to test without hitting the database entirely. At some point you want to test the whole stack. Every time you mock or stub you are making an assumption about an interface that may contain subtle bugs. So, assuming that you need to hit the database on some significant percentage of tests, transactional fixtures (you are using transactional fixtures right?) could well be much much faster than instantiating a whole environment for every test.

I'd say, with the size of your test suite that you really need to look towards Continuous Integration to scale your development to the next level. No matter how much you speed them up, it's still a long time for developers to wait. Maybe look at autotest as well to help at the individual level. But ultimately CI is going to allow you to maintain testing discipline without sacrificing developer agility.

The place where fixtures really shine is in functional/integration testing. The way I look at it is that the fixtures should set up a healthy base state for the app to be tested. Most unit tests don't really need this. You can get very good unit coverage using factories. However when it comes to functional testing, any given page may be hitting dozens of models. I don't want to set up all that stuff in each test. As I construct ever more complex scenarios, I'm getting closer and closer to recreating a global data state which is exactly what fixtures were designed to do in the first place.

One controversial belief I hold is that all else being equal, I prefer one functional test to 20 unit tests (using Rails parlance). Why? Because the functional test proves that the end result that is sent to the user is correct. The unit tests are great for getting at nuances of functionality, but at the end of the day, you could still have a bug along an interface that breaks your entire site. Functional tests are what give me the confidence hitting deploy without actually loading up the page in my browser. I know that I could stub everything out and test both interfaces and get the same coverage, but if I can test the whole stack in one simple test at the expense of a little CPU, I'd much rather do that.

So what are my best practices for fixtures?

  • Set up a handful for every model to cover the broadest categories of data
  • When adding a major new feature that cuts across many models and controllers, add some new fixtures to represent the major states
  • Avoid editing old fixtures except for adding/removing fields
  • Use factories for more smaller/more localized variations
  • Use factories for testing pagination or other mass creation that is only needed for a few tests

Also, let me recommend Jay Fields' blog for really good pragmatic testing advice. The thing I like most about Jay's blog is that he always acknowledges that testing is very project-specific, and what works for one project does not necessarily work for another. He's short on dogma and long on pragmatism.

疯了 2024-07-24 07:18:49

为了获得良好的测试套件而设置实体之间的所有依赖关系可能会出现一些问题。 无论如何,这仍然比维护大量的固定装置容易得多。

Fixtures:

  • 关系很难维持(尤其是多对多);
  • 由于更多的数据库命中,测试套件运行时间通常会更慢;
  • 测试对模式的变化非常敏感。

工厂:

  • 你对当前单元测试中未测试的所有内容进行存根;
  • 您准备要与工厂一起测试的实体。 这就是工厂展示其真正优势的地方——很容易设置新的测试用例,因为您不需要为此维护大量的 YAML 文件;
  • 你专注于测试。 如果测试需要改变场景,你就不会改变你的心态。 只要存根合理并且工厂易于定制,就应该没问题。

因此,工厂似乎是一个不错的选择。 我认为唯一可能的缺点是:

  • 从固定装置迁移所花费的时间;
  • 保持一组合理的场景可能需要一些努力。

There could be some issues with setting up all dependencies between entities for good test suite. Anyway, it's still much easier than maintaing a lot of fixtures.

Fixtures:

  • hard to maintain relationships (especially many-to-many);
  • test suite runtime is usually slower due more DB hits;
  • tests are very sensitive to changes in schema.

Factories:

  • you stub everything you don't test at current unit test;
  • you prepare entities that you are testing with factories. This is where factories show their real advantage — it's easy to set up new test cases, as you don't need to maintain a ton of YAML-files for that;
  • you concentrate on testing. If tests require changing scenario, you don't shift your mindset. As long as stubs are reasonable and factories are easily customized, you should be fine.

So, factories seem a good way to go. The only possible drawbacks I see, are:

  • time you spent migrating from fixtures;
  • keeping a sane set of scenarios can require some effort.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文