在未接触 rspec 之前,大量使用过 c, python, nodejs, php,但测试方面基本都是空白。现在想来,很多时候不是开发者不想写测试,而是并没有好的测试工具,不够灵活。写测试的难度很多时候都快等于开发了,甚至高过开发。
先写出完备的测试,再去填坑,将失败的测试逐个通过,开发的过程变成了填坑通关的过程。
不少情况下,代码的运行逻辑和时间相关,如到了提前设定的时间范围内,执行 xxx 函数。这种情况下的测试,一般会将时间判断,单独抽离出来成为一个函数,对它进行测试,这时候,我们就需要 faker 时间了,不可能真等到设定的时间范围内。 使用timecop来 faker 时间,如下面例子,将当前的时间 Tim.now, 设定到 end_time 前 5s,以保证在时间范围内。
it "pass test now_is_in_order_flow_on_peroid?" do
Timecop.freeze(@end_time - 5) do
expect(Spree::Order.now_is_in_order_flow_on_peroid?).to eq true
end
end
代码中很可能使用 whenever 这样的 gem, 执行些定时任务,怎么测试呢? whenever 类似的 gem, 达到的效果是帮你生成相应的 crontab 任务,它做的事情其实是和我们的代码逻辑无关的。 我的理解是,如果是定时每隔 5 分钟,要执行下 model.xxx 函数,那实际上我们直接在 rspec 中调用 model.xxx 函数对其进行测试即可。 而如果要测试 whenever 的 crontab 语句生成是否正确,请参考https://github.com/javan/whenever/blob/master/test/unit/cron_test.rb , 大部分情况下,是没有必要对其进行测试的,如果是简单的每隔 xx 分钟/小时。
在 web 的测试中,基本都会去检验是否登录,以及部分代码是登录后才能去执行,那在 model, controller 中,会有大量的测试,需要进行提前登录,这时候就需要使用 helper,在 support 中建立 login_helpers.rb,加入 login_user, login_admin, login_staff 这些函数,在需要做登录的测试中,引入 login_user 即可。
def login_user
before(:each) do
user = FactoryGirl.create(:user)
controller.send(:login_as, user)
end
end
因 rspec 测试并不会去读取 db/seeds 中的数据,但 model,controller 中的许多逻辑测试,可能依赖于某部分数据的提前建立,这时候可以在 support 中建立 data_helpers.rb, 加入 set_init_data 类似的函数,供所有测试去公用这段初始化数据的代码
许多情况下,需要伪造 email, name 这些类似的信息,可以使用 faker,随机出字符串和名字等等信息
FactoryGirl.define do
sequence(:random_string) { Faker::Lorem.sentence }
sequence(:random_name) { Faker::Name.name }
end
而如果要求是 uniq, 因为要确保 uniq, 变量的一部分就需要每次都不一样,这可以是 timestamp, 也可以是 n(0,1,2..),每次都不一样
sequence(:sku) { |n| "SKU-#{n}" }