序言
这是我第一次尝试使用SRP构建应用程序,并且真正尝试使用测试来驱动网站的代码,而不是从我的数据架构(ActiveRecord)开始,然后构建适合的应用程序。 / p>
但我遇到了问题。我已经订阅并观看了大量的Destroy All Software截屏视频,理论上我喜欢他所宣传的内容,但我在实践中遇到了麻烦。
手头的问题
我知道我应用的主要功能是根据位置搜索个人资料。所以我为此编写了一个简单的Cucumber功能(故意暂时离开路由/控制器/等以简化手头的任务)。
search.feature:
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类。
我不确定接下来要做什么。 ProfileSearch
显然取决于Profile
模型,我很确定这将是ActiveRecord。
所以问题是我是否开始指出并构建Profile
并在我的测试中开始加载Rails?这似乎是最简单的选择,但有些事情似乎是错误的。我觉得我会设计并构建我的应用尚未特别要求的行为。我不得不考虑字段,关系和存储等,所有这些都是我的应用目前不应该关心的。
或者我应该在我的Profile
规范中对ProfileSearch
的所有调用使用存根/模拟,并确保调用正确的方法?这似乎也是错误的,因为我当时并不会真正测试这种行为,并且在切换到Solr或ElasticSearch时我必须重写测试,即使预期会出现相同的行为。
或者我应该创建一个暂时不使用ActiveRecord的工作Profile模型,但正如Uncle Bob在构建他的wiki时演示的那样正确响应所有正确的方法?这似乎可能是理论上最好的方法,但是知道我将来会使用ActiveRecord它似乎也是多余的。
或者... f * ck并将所有内容都放在ActiveRecord模型中:\
我脑子里浮现的模式,原则和最佳实践有很多,我不知道要做什么。
你会做什么?
答案 0 :(得分:1)
首先,您需要选择测试方法:
Cucumber专为BDD(从外到内)测试而设计。黄瓜场景旨在锻炼整个堆栈(网页,控制器,模型,数据库 - 或任何堆栈),而不是像上面那样用作单元测试。因此,如果您编写的第一件事是Cucumber场景,那么您需要调用所有层以使第一个场景通过。这就是我所做的,无论是使用Cucumber(我最喜欢的)还是RSpec功能规格。完成后,您可以自由地重构以满足您喜欢的任何设计标准,并且您可以通过单元测试来测试详细要求。
或者,您可以选择堆栈中最棘手的部分,对其进行单元测试,然后对图层进行单元测试,最后进行验收测试,直到您拥有一个完整的应用程序。一方面,在投资简单零件之前,证明您可以使用棘手的部件可能是一个好主意。另一方面,我发现当我猜测没有工作验收测试的组件接口时,我总是猜错了,所以我不这样做。
无论哪种方式,您的目标都是ProfileSearch
类,它返回Profile
个实例,但并不承诺它们是ActiveRecord对象或其他任何持久性特定的对象。如何在测试中处理这些类取决于测试的类型:
如果您使用验收规范(Cucumber或RSpec功能规范),他们将不会使用存根,他们将使用所有真正的实现类,并且他们将加载Rails,因为它'他们的观点以及他们如何设计。对不起,他们会很慢。不要再写下你指定重要场景所需的内容了。
在使用ProfileSearch
的类的单元测试中,您可以将其存根并返回PORO以获得速度。 (如果您在这些规范中使用了rspec-rails,require 'spec_helper'
而不是rails_helper
,以避免在自行运行Rails时加载Rails。)
让ProfileSearch
本身的单元测试通过的最简单方法可能就是让Profile
成为ActiveRecord模型并让ProfileSearch
使用Profile
&#39 ; s ActiveRecord功能并返回Profile
的实例。这些规范也需要require 'rails_helper'
。