【问题标题】:Rails Testing: Fixtures, Factories, and Magic numbersRails 测试:夹具、工厂和幻数
【发布时间】:2010-09-18 16:24:30
【问题描述】:

我有一个应用程序需要大量数据(1000 条记录)来进行适当的测试。我发现获得一组体面的可测试、合理的数据的唯一方法是使用我的生产数据库的子集。我已将其转换为正常“测试/固定装置”位置的 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

这对我来说似乎不是一个好主意,但我不确定是否有更好/可接受的方法来测试需要大量数据层次结构的应用程序。 p>

【问题讨论】:

    标签: ruby-on-rails unit-testing testing yaml


    【解决方案1】:

    我要说的第一件事是:您在该示例中测试什么?如果它是一个普通的 AR has_many 关联,那么我不会费心为它编写测试。您所做的只是测试 AR 是否有效。

    如果您有一个非常复杂的查询,或者在获取子记录列表时涉及其他处理,则可能是一个更好的例子。当您取回它们时,您可以遍历返回的列表并验证子项是否符合您使用的条件,而不是测试计数。

    【讨论】:

    • 是的,在那个例子中它只是一个 ActiveRecord 关联。我已经开始使用 Shoulda,它提供了诸如 should_have_many 之类的帮助器:children,这让它变得容易多了。
    【解决方案2】:

    我发现在这种情况下最有用的是根本不使用固定装置,而是像

    那样动态构建数据库对象
    def test_foo
       project = Project.create valid_project.merge(....)
       *do assertions here*
    end
    

    在我的 test_helpers 中,我有一堆方法:

    def valid_project
       { :user_id => 23, :title => "My Project" }
    end
    
    def invalid_project
       valid_project.merge(:title => nil)
    end
    

    我发现,不得不构建大量测试对象的痛苦使我自然而然地设计了更简单、更通用的类结构。

    【讨论】:

    【解决方案3】:

    测试中的幻数不是反模式。您的测试需要非常简单,以至于您不需要测试它们。这意味着你会有一些神奇的数字。这意味着当您更改少量功能时,您的测试将中断。这很好。

    夹具有some problems,但您可以做一些简单的事情来让它们更容易使用:

    1. 在您的夹具中只有基线数据,大多数测试需要但不关心的数据类型。这需要预先投入时间,但最好早点承受痛苦,而不是在项目的整个生命周期中编写糟糕的单元测试。

    2. 在测试的上下文中添加要测试的数据。这提高了您的测试的可读性,并让您免于在单元测试开始时编写“确保没有人弄乱固定装置”的健全性检查。

    【讨论】:

    • 这与thoughtbot rails 插件Shouda 相结合,使得在测试方法子组上运行设置和拆卸变得非常容易,保持您的测试代码干燥。
    【解决方案4】:

    Cameron 说得对:你在测试什么?

    什么样的系统需要 1000 条记录来测试?请记住,您的测试应该尽可能小,并且应该测试应用程序的行为。绝大多数测试都需要数千条记录。

    对于需要对象关系的少量行为测试,请考虑模拟对象。您只需指定使测试通过所需的确切最小行为量,它们根本不会影响数据库,这将在您的测试套件中获得巨大的性能提升。跑得越快,人们跑得越频繁。

    【讨论】:

    • 经过一些优化,我把需求降到了5张表只有150条左右的记录,这是一个数据分析应用程序。
    【解决方案5】:

    我在这里可能有一个独特的情况,但我确实需要相当多的记录来测试这个应用程序(我把它降到了 150 条左右)。我正在分析历史数据并且有多个级别的has_many。我的一些方法对多个表进行自定义 SQL 查询,我最终可能会将其修改为使用 ActiveRecord.find,但我需要先运行测试。

    无论如何,我最终使用了一些 ruby 代码来创建固定装置。代码包含在我的test_helper;它检查测试数据库以查看数据是否过时(基于时间条件)并擦除并按程序重新创建记录。在这种情况下,通过程序创建它可以让我知道我正在测试的数据是什么应该,这比使用生产数据的子集更安全并希望得到数字我计算了第一次是我将来应该测试的。

    我也开始使用Shoulda,它与许多其他有用的东西一起使 ActiveRecord 关联测试变得如此简单:

    should_have_many :children
    should_belong_to :parent
    

    【讨论】:

    • 那么,您在运行测试时根据生产数据重新创建了记录?成功了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    相关资源
    最近更新 更多