Rails 测试:装置、工厂和幻数
我有一个应用程序需要大量数据(数千条记录)才能进行适当的测试。 我发现获得一组像样的可测试、合理数据的唯一方法是使用生产数据库的子集。 我已将其转换为正常“测试/装置”位置中的 YAML 装置。
这是可行的,但现在我有一堆看似脆弱的测试和断言,它们取决于它们是满足条件 X 的特定数量的记录...
示例
def test_children_association
p = Parent.find(1)
assert_equal 18, p.children.count, "Parent.children isn't providing the right records"
end
这对我来说似乎不是一个好主意,但是我不确定是否有更好/可接受的方法来测试需要大量数据层次结构的应用程序。
I've got an application that needs quite a bit of data (1000s of records) to do appropriate testing. The only way I've found to get a decent set of testable, sensible data is to use a subset of my production DB. I've converted this to YAML fixtures in the normal `test/fixtures' location.
This works, but now I have a bunch of seemingly brittle tests and assertions that depend on their being a particular number of records that meet condition X...
example
def test_children_association
p = Parent.find(1)
assert_equal 18, p.children.count, "Parent.children isn't providing the right records"
end
This doesn't seem like a good idea to me, but I'm not sure if there is a better / accepted way to test an application that needs a large hierarchy of data.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
测试中的幻数并不是反模式。 您的测试必须非常简单,以至于您不需要测试它们。 这意味着您将拥有一些神奇的数字。 这意味着当您更改少量功能时,您的测试将会中断。 这很好。
灯具有一些问题,但有您可以做一些简单的事情来使它们更易于使用:
在您的装置中仅包含基线数据,这是大多数测试需要但不关心的数据。 这将需要预先投入时间,但最好尽早承受痛苦,而不是在项目的整个生命周期中编写糟糕的单元测试。
在测试上下文中添加要测试的数据。 这提高了测试的可读性,并使您无需在单元测试开始时编写“确保没有人弄乱固定装置”的健全性检查。
Magic numbers in tests aren't an anti-pattern. Your tests need to be so dead-simple that you don't need to test them. This means you'll have some magic numbers. This means that your tests will break when you change small bits of functionality. This is good.
Fixtures have some problems, but there are a few simple things you can do to make them easier to work with:
Only have baseline data in your fixtures, the sort of data that most of your tests need but don't care about. This will involve a time investment up front, but it's better to take the pain early than write poor unit tests for the life of the project.
Add the data to be tested in the context of the test. This improves readability of your tests and saves you from writing "make sure nobody messed up the fixtures" sanity checks at the beginning of your unit tests.
我要说的第一件事是:您在该示例中测试什么? 如果它是一个普通的 AR has_many 关联,那么我就不会费心为它编写测试。 您所做的只是测试 AR 是否有效。
一个更好的例子可能是,如果您有一个非常复杂的查询,或者获取子记录列表涉及其他处理。 当您取回它们时,您可以迭代返回的列表并验证子项是否符合您正在使用的条件,而不是测试计数。
The first thing I'd say is: what are you testing in that example? If it's an ordinary AR has_many association, then I wouldn't bother writing a test for it. All you're doing is testing that AR works.
A better example might be if you had a very complicated query or if there was other processing involved in getting the list of children records. When you get them back, rather than testing for a count you could iterate through the returned list and verify that the children match the criteria you're using.
我发现在这种情况下最有用的是根本不使用固定装置,而是像在我的 test_helpers 中一样动态构建数据库对象,
我有很多方法:
我发现必须构建大量集合的痛苦测试对象的数量让我自然地设计出更简单、更通用的类结构。
what I've found most useful in this situation is not using fixtures at all but rather construct the database objects on the fly like
and in my test_helpers I'd have a bunch of methods:
I found that the pain of having to build massive collections of test objects has led me naturally to design simpler and more versatile class structures.
卡梅伦说得对:你在测试什么?
什么样的系统需要数千条记录来测试? 请记住,您的测试应该尽可能小,并且应该测试应用程序行为。 绝大多数测试不可能需要数千条记录。
对于需要对象关系的少量行为测试,请考虑模拟对象。 您只需指定让测试通过所需的最少量行为,并且它们根本不会影响数据库,这将在您的测试套件中带来巨大的性能提升。 跑得越快,人们跑步的次数就越多。
Cameron's right: What are you testing?
What sort of system needs 1000s of records present to test? Remember, your tests should be as tiny as possible and should be testing application behavior. There's no way it needs thousands of records for the vast majority of those tests.
For little bits of behavior tests where you need object relationships, consider mock objects. You'll only be speccing out the exact minimum amount of behavior necessary to get your test to pass, and they won't hit the DB at all, which will amount to a huge performance gain in your test suite. The faster it is to run, the more often people will run it.
我这里可能有一个独特的情况,但我确实需要相当多的记录来测试这个应用程序(我把它减少到 150 左右)。 我正在分析历史数据,并且有多个级别的
has_many
。 我的一些方法跨多个表执行自定义 SQL 查询,我最终可能会修改这些表以使用 ActiveRecord.find,但我需要先运行测试。不管怎样,我最终使用了一些ruby 代码来创建灯具。 该代码包含在我的
test_helper
中; 它检查测试数据库以查看数据是否过时(基于时间条件)并擦除并按程序重新创建记录。 在这种情况下,按程序创建它可以让我知道我正在测试的数据应该是什么,这比使用生产数据的子集更安全并希望得到数字我计算出第一次是我以后应该测试的。我还转向使用 Shoulda ,它与许多其他有用的东西一起使 ActiveRecord 关联测试变得简单作为:
I may have a unique situation here, but I really did need quite a few records for testing this app (I got it down to 150 or so). I'm analyzing historical data and have numerous levels of
has_many
. Some of my methods do custom SQL queries across several tables which I might end up modifying to useActiveRecord.find
but I needed to get the test running first.Anyway, I ended up using some ruby code to create the fixtures. The code is included in my
test_helper
; it checks the test DB to see if the data is stale (based on a time condition) and wipes and recreates the records procedurally. In this case, creating it procedurally allows me to know what the data I'm testing for SHOULD be, which is safer than using a subset of production data and hoping the numbers I calculate the first time are what I should test for in the future.I also moved to using Shoulda which along with many other useful things makes ActiveRecord Association testing as easy as: