2

前言

这是我第一次尝试在考虑 SRP 的情况下构建应用程序,并真正尝试使用测试来驱动网站的代码,而不是从我的数据架构 (ActiveRecord) 开始,然后构建适合的应用程序。

但我遇到了问题。我订阅并观看了很多 Destroy All Software 的截屏视频,理论上我喜欢他所宣扬的内容,但我在实践中遇到了麻烦。

手头的问题

我知道我的应用程序的主要功能是根据位置搜索个人资料。因此,我为此编写了一个简单的 Cucumber 功能(暂时不使用路由/控制器/等,以简化手头的任务)。

搜索功能:

Feature: Search for profiles

  Scenario: By zipcode
    When I search for 90210
    Then I will see profiles near 90210

search_steps.rb:

When /^I search for 90210$/ do
  @profiles = ProfileSearch.new.near_location(90210).all
end

Then /^I will see profiles near 90210$/ do
  pending # express the regexp above with the code you wish you had
end

没问题,现在看规格:

profile_search_spec.rb:

require_relative '../../app/services/profile_search'

describe ProfileSearch do  
  it "finds nearby profiles"
  it "does not find far away profiles"
end

profile_search.rb:

class ProfileSearch
end

我使用 ProfileSearch 类有几个原因。

  1. 将尽可能多的业务逻辑移到 ActiveRecord(单一职责原则)之外似乎是正确的做法。
  2. PORO 可以加快测试速度(不加载 Rails)。
  3. 我计划在不久的将来使用 ElasticSearch 或 Solr,并希望界面保持不变。

我不确定下一步该怎么做。ProfileSearch显然取决于Profile模型,我很确定这将是 ActiveRecord。

所以问题是我是否开始规范和构建Profile并开始在我的测试中加载 Rails?这似乎是最简单的选择,但似乎有些错误。我觉得我会设计和构建我的应用程序尚未特别要求的行为。我将不得不考虑字段、关系和存储等,所有这些都是我的应用程序目前不应该关心的。

Profile或者我应该对规范中的所有调用使用存根/模拟,ProfileSearch并确保调用了正确的方法?这似乎也是错误的,因为那时我不会真正测试该行为,并且在切换到 Solr 或 ElasticSearch 时我必须重写测试,即使预期会有相同的行为。

或者我实际上应该创建一个工作的 Profile 模型,它暂时不使用 ActiveRecord,但可以正确响应 Bob 叔叔在构建他的 wiki 事物时展示的所有正确方法?从理论上讲,这似乎是最好的方法,但知道我将来会使用 ActiveRecord,这似乎也很多余。

或者...去他妈的,把所有东西都扔到 ActiveRecord 模型中:\

有太多的模式、原则和最佳实践在我脑海中浮现,我不知道 WTF 该怎么做。

你会怎么做?

4

1 回答 1

1

首先,您需要选择测试方法:

  • Cucumber 专为 BDD(由外而内)测试而设计。Cucumber 场景旨在锻炼您的整个堆栈(网页、控制器、模型、数据库——或任何您的堆栈),而不是像您在上面所做的那样用作单元测试。因此,如果您编写的第一件事是 Cucumber 场景,则需要调用所有层以使第一个场景通过。这就是我所做的,无论是使用 Cucumber(我最喜欢的)还是 RSpec 功能规范。完成之后,您可以自由地重构以满足您喜欢的任何设计标准,并且您可以通过单元测试来测试详细的需求。

  • 或者,您可以选择堆栈中最棘手的部分,对其进行单元测试,然后在各层上下进行单元测试,最终进行验收测试,直到您拥有整个应用程序。一方面,这可能是一个好主意,可以证明您可以在投资简单的部分之前让棘手的部分工作。另一方面,我发现当我在没有工作验收测试的情况下猜测组件接口时,我总是猜错,所以我不这样做。

无论哪种方式,您的目标都是ProfileSearch返回Profile实例但不保证它们是 ActiveRecord 对象或任何其他持久性特定的类。在测试中如何处理这些类取决于测试的类型:

  • 如果您使用验收规范(Cucumber 或 RSpec 功能规范),它们将不使用存根,它们将使用所有真正的实现类,并且它们将加载 Rails,因为这是它们的重点,也是它们的设计方式。对不起,他们会很慢。除了指定重要场景所需的内容之外,不要编写更多内容。

  • 在使用 的类的单元测试中ProfileSearch,您可以将其存根并返回 PORO 以提高速度。(如果您使用 rspec-rails,require 'spec_helper'而不是rails_helper在那些规范中,以避免在您自己运行 Rails 时加载它们。)

  • 让自己的单元测试ProfileSearch通过的最简单方法可能是只创建Profile一个 ActiveRecord 模型并ProfileSearch使用Profile的 ActiveRecord 功能并返回Profile. 这些规格也需要require 'rails_helper'

于 2016-02-14T03:03:20.373 回答