第三方库的单元测试

时间:2009-10-31 23:58:05

标签: ruby-on-rails

我正在开发我的第一个真实世界的Rails项目。到目前为止,我主要是从第三方库中混搭功能。那里有很多伟大的,那太好了。

我想知道围绕这些库编写单元测试是否必要/有用。例如,我只在我的一个模型周围集成了friendly_id。除了安装gem并将其添加为项目依赖项之外,此集成的这个程度还包括:

has_friendly_id :name

它刚刚工作,我几乎不认为这是“我写的代码”。那么我应该通过测试来写作呢?

我的问题有两点需要注意:

  1. 我假设我的所有第三方库都有自己的相应测试 - 因此直接针对这些库编写新的单元测试就像重复代码一样。 (如果我不得不使用经过严格测试的库,那么我就不会为它编写测试而犹豫不决。)
  2. 在缺陷驱动测试下,我肯定会在第二次遇到问题时编写测试。如果测试发现了库中的错误,那么我可能会将测试提交给维护者。
  3. 除此之外......测试第三方代码有多大意义?

5 个答案:

答案 0 :(得分:2)

通常的做法是对其他一方的代码进行单元测试。通常,您会相信您的上游依赖项可以正常工作。

但是假设你真的相信他们。这应该有各种各样的原因。

首先,你会陷入一种近乎被抛弃的依赖关系,其中包含一些错误的错误。当您发现错误时,编写测试来执行错误并为错误运行解决方法。

另一个原因可能是因为第三方不断改变每一件该死的东西。因为你可以腾出时间,所以添加你实际使用的尘埃角落的测试是合理的,因为在新版本中你最容易改变它们。

显然,这些案例中的任何一个都会浪费你宝贵的时间,你可能会花费更多的时间来改善你的应用程序,而不是处理你无法控制的事情。如果您发现需要进行此类测试,那么您应该真正寻找一种更可信赖的替代方案来替代该特定依赖项。

答案 1 :(得分:2)

永远不要相信第三方库。我总是写一组测试,我称之为第三方库的“健全性检查”,但我只将其应用于一个模型/控制器/无论如何。因此,例如,如果我使用acts_as_paranoid gem(它使数据库记录看起来被删除但实际上没有删除它),我将为只使用扩展的模型的一个编写一组测试,并假设它适用于其余的人。这让我可以在晚上睡觉,知道我可以在新版本发布时更新gem,甚至使用“edge”版本,并且预期的功能将是可靠的。

答案 2 :(得分:1)

根据经验,以下是我的意见:

  • 请勿在您的网络应用中测试第三方库。分叉它们,确保它们在自身内部进行单元测试,并依赖于您的分支(或版本或提交或标记),直到您准备好升级到下一个版本。如果发现错误,请在fork上进行更改并向官方存储库发送拉取请求。在将错误拉入主线之前,请使用自己的分叉。
  • 制作适配器层(调用第三方服务的模块或类)是一个好主意,但更适合图书馆或宝石而不是Web应用程序代码库。关于适配器的一个好处是,你可以让它们的Mock版本只在测试环境中加载。
  • 使用WebMock或FakeWeb或Artifice或......模拟外部http调用,然后列表继续。确保告诉实用程序不允许在测试环境中进行外部调用。
  • 也许使用VCR在后续测试运行中记录和模拟所有http请求(关于VCR的一个警告 - 它非常有用,但要警惕使用带有更大代码库的自动盒式磁带命名策略 - 任何应用程序范围的更改会使你的大多数自动生成的磁带变得无用。如果你只是使用VCR.use_cassette('cassete-name') do块,它应该与使用WebMock / Fakeweb / Artifice等非常相似。后者是我的首选。)

答案 3 :(得分:0)

不,您不应该测试第三方代码,如果可能,它应该位于界面后面,以便您可以根据需要轻松更换功能。
该接口允许您在代码中使用模拟,以模拟对库的调用。

答案 4 :(得分:0)

不要写单元测试,而是写集成!


countries gem 的简短示例:

require 'test_helper'

class CountriesLearningTest < ActiveSupport::TestCase
  def test_returns_country_name
    assert_equal 'United States of America', Country.new('US').name
  end

  def test_returns_country_alpha2_code
    assert_equal 'US', Country.new('US').alpha2
  end
end

我认为可以安全地假设库的单元测试已经足够好了。但是,出于以下原因,编写所谓的学习(或发现)集成测试可能是有益的:

  • 如果依赖项是全新的,它可以让您更熟悉 3rd 方 API。
  • 与任何其他好的测试一样,它充当文档,因此其他程序员(包括以后的您)将不需要玩弄该库来了解它是如何工作的。
  • 在项目中使用库的方式变得更加明显。
  • 在将库更新到可能包含不兼容更改的主要版本时,它充当安全网。

paper_trail gem 的另一个示例:

require 'test_helper'

class Post < ApplicationRecord
  has_paper_trail
end

class PaperTrailLearningTest < ActiveSupport::TestCase
  setup do
    ActiveRecord::Base.connection.create_table :posts do |t|
      t.string :title

      # Otherwise `touch` fails silently
      t.datetime :updated_at
    end
  end

  def test_returns_version_list
    @record = Post.create!(title: 'any')

    assert_equal 1, @record.versions.count
    assert_respond_to @record.versions.first, :item_id
  end

  def test_creates_new_version_upon_update
    @record = Post.create!(title: 'old title')
    original_record = @record.clone

    assert_difference -> { @record.versions.size } do
      @record.update!(title: 'new title')
    end
    version = @record.versions.last
    assert_equal @record.id, version.item_id
    assert_equal @record.class.name, version.item_type
    assert_equal version.reify, original_record
    assert_equal ['old title', 'new title'], version.object_changes['title']
    assert_equal 'update', version.event
  end
end
相关问题