2

我目前正在查看一个庞大的 Rails 测试套件。我无法详细说明,但整个套件(单元/功能/某些集成)的运行时间可以超过 5 分钟。

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

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

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

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

谢谢!

4

2 回答 2

11

奥列格的回答很好,但让我提供一个同时使用两者的人的观点。

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.

于 2009-04-20T18:30:56.490 回答
6

为良好的测试套件设置实体之间的所有依赖关系可能存在一些问题。无论如何,它仍然比维护很多固定装置要容易得多。

夹具:

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

工厂:

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

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

  • 您从固定装置迁移所花费的时间;
  • 保持一组理智的场景可能需要一些努力。
于 2009-04-20T14:33:10.663 回答