ãã¤ã³ãã·ã¹ãã (3) -- timecop
2013/09/30
ååã«å¼ãç¶ããããã¤ã³ãã·ã¹ãã ãã®å®è£ ãç¶ãã¾ããä»åã¯ãããã°ã¤ã³ãã¤ã³ãã¯ã¦ã¼ã¶ã¼ãã¨ã«1æ¥1åããä¸ããããªããã¨ããä»æ§ã®ãã¹ãã¨å®è£ ã§ãã
timecop
æéã®çµéã«é¢é£ããä»æ§ã®ãã¹ããæ¸ãéã«ã便å©ãªã®ã timecop
ã¨ãã Gem ããã±ã¼ã¸ã§ããããããæéæ
è¡ããããã®ããã« Time.current
ã Date.today
ãè¿ãå¤ãä¸æçã«å¤æ´ãã¦ããã¾ãã
ã¾ãã¯ãã¤ã³ã¹ãã¼ã«ãGemfile
ã次ã®ããã«å¤æ´ãã¦ãã ããï¼
# (çç¥) group :test do gem 'rspec-rails' gem 'capybara' gem 'factory_girl_rails', '~> 4.2.1' gem 'timecop' end
ã¿ã¼ããã«ã§æ¬¡ã®ã³ãã³ããå®è¡ãã¾ãã
$ bundle
ãã¹ããæ¸ã
ãã°ã¤ã³ãã¤ã³ãã®æ£ç¢ºãªä»æ§ã¯ã次ã®éãã§ãï¼
- ã¦ã¼ã¶ã¼ããã°ã¤ã³ã«æåããã¨ãããã°ã¤ã³ãã¤ã³ããã¨ãã¦ã¦ã¼ã¶ã¼ã«1ãã¤ã³ããä¸ããããã
- ãã ããããã°ã¤ã³ãã¤ã³ããã¯ã¦ã¼ã¶ã¼ãã¨ã«1æ¥1åããä¸ããããªããæ¥ã®åºåãã¯æ¥æ¬æéåå5æã¨ããã
- ã¾ããåææ¥ã«ãã°ã¤ã³ããã¨ãé常ã®ããã°ã¤ã³ãã¤ã³ããã®ä»ã«ãåæãã°ã¤ã³ãã¼ãã¹ãã¨ãã¦2ãã¤ã³ããä¸ããããã
ä»åã¯ç¬¬2ã®ä»æ§ã®ãã¹ããæ¸ãã¦ãå®è£ ãã¾ãã
spec/models/customer_spec.rb
ã® .authenticate
ã¡ã½ããã®ã¨ã°ã¶ã³ãã«ã°ã«ã¼ãã«æ¬¡ã®ã¨ã°ã¶ã³ãã«ãæ¿å
¥ãã¾ãã
specify 'æ¥ä»å¤æ´æå»ãã¾ããã§2åãã°ã¤ã³ããã¨ãã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã2å¢ãã' do Time.zone = 'Tokyo' date_boundary = Time.zone.local(2013, 1, 1, 5, 0, 0) expect { Timecop.freeze(date_boundary.advance(seconds: -1)) Customer.authenticate(customer.username, 'correct_password') Timecop.freeze(date_boundary) Customer.authenticate(customer.username, 'correct_password') }.to change { customer.points }.by(2) end specify 'æ¥ä»å¤æ´æå»ãã¾ãããã«2åãã°ã¤ã³ãã¦ããã¦ã¼ã¶ã¼ã®ä¿æãã¤ã³ãã¯1ããå¢ããªã' do Time.zone = 'Tokyo' date_boundary = Time.zone.local(2013, 1, 1, 5, 0, 0) expect { Timecop.freeze(date_boundary) Customer.authenticate(customer.username, 'correct_password') Timecop.freeze(date_boundary.advance(hours: 24, seconds: -1)) Customer.authenticate(customer.username, 'correct_password') }.to change { customer.points }.by(1) end
ã¾ã Time.zone = 'Tokyo'
ã§ã¿ã¤ã ã¾ã¼ã³ãæ¥æ¬æéã«è¨å®ãã¦ãã¾ãããã㯠Rails ã®æ©è½ã§ãã次ã«ãé©å½ãªæ¥ä»ã®åå5æãå¤æ° date_boundary
ã«ã»ãããã¦ãã¾ãã
1çªç®ã®ã¨ã°ã¶ã³ãã«ã§ã¯ãæ¥ä»å¤æ´æå»ã®1ç§åã«ç¾å¨æå»ã移ãã¦ãã°ã¤ã³ããããã«1ç§é²ãã¦ãã°ã¤ã³ãã¦ãã¤ã³ãã2å¢ãããã¨ã確èªãã¾ãã2çªç®ã®ã¨ã°ã¶ã³ãã«ã§ã¯æ¥ä»å¤æ´æå»ã¡ããã©ã«ãã°ã¤ã³ããå¾ãç¿æ¥ã®æ¥ä»å¤æ´æå»ã®1ç§åã«ç¾å¨æå»ãé²ãã¦ãã°ã¤ã³ãããã¤ã³ãã1ããå¢ããªããã¨ã確èªãã¾ãã
ç¾å¨æå»ã®ç§»åã«ã¯ Timecop.freeze
ã¡ã½ããã使ç¨ãã¾ãããã®ã¡ã½ããã¯ä¸ããããæå»ãç¨ãã¦ãTime.current
ã Date.today
ã®ã¹ã¿ããä½ãã¾ãããã®çµæããã¹ã対象ã®ã·ã¹ãã ã«ã¯ç¾å¨æå»ã移åããããã«è¦ãããã¨ããããã§ãã
å®è£
ä»åã¯ã½ã¼ã¹ã³ã¼ãã®å¤æ´ç®æã示ãã ãã«ãã¾ãï¼ç ããªã£ã¦ãã¾ããâ¦ï¼ã
æ¸ãæãåã®ã³ã¼ãï¼
require 'nkf' require 'bcrypt' class Customer < ActiveRecord::Base # (çç¥) class << self def authenticate(username, password) customer = find_by_username(username) if customer.try(:password_digest) && BCrypt::Password.new(customer.password_digest) == password customer.rewards.create(points: 1) customer else nil end end end end
æ¸ãæãå¾ã®ã³ã¼ãï¼
require 'nkf' require 'bcrypt' class Customer < ActiveRecord::Base # (çç¥) class << self def authenticate(username, password) customer = find_by_username(username) if customer.try(:password_digest) && BCrypt::Password.new(customer.password_digest) == password Time.zone = 'Tokyo' now = Time.current if now.hour < 5 time0 = now.yesterday.midnight.advance(hours: 5) time1 = now.midnight.advance(hours: 5) else time0 = now.midnight.advance(hours: 5) time1 = now.tomorrow.midnight.advance(hours: 5) end unless customer.rewards.where(created_at: time0...time1).exists? customer.rewards.create(points: 1) end customer else nil end end end end
ãã¤ã³ã㯠where(create_at: time0...time1).exist?
ã¨ããã¨ãããããã§ãããããtime0
ãã time1
ã¾ã§ã®éï¼ç«¯ç¹ time1
ã¯å«ã¾ãªãï¼ã« rewards
ãã¼ãã«ã«æ¿å
¥ãããã¬ã³ã¼ãã®æç¡ã調ã¹ã¦ãã¾ãã
ããã§ãã¹ãã¯éãã¾ãããããããã®ã³ã¼ãã¯ã¾ã æªå®æã§ãããã°ã¤ã³ä»¥å¤ã®çç±ã§ä¸ãããããã¤ã³ããã«ã¦ã³ããã¦ãã¾ãããã§ãããã®ç¹ã«ã¤ãã¦ã¯ããã¨ã§èãããã¨ã«ãã¾ãããã
次åã¯
å®è£
ãä¸ååã§ããäºå®ããã大ããªåé¡ã¯ãCustomer.authenticate
ã¡ã½ãããè¥å¤§åãã¦ãããã¨ã§ãããã®ã¡ã½ããã®æ¬æ¥ã®å½¹å²ã¯ã¦ã¼ã¶ã¼ãèªè¨¼ãããã¨ã§ããããã¤ã³ããä¸ããã¨ãä¸ããªãã¨ãå¤æããã®ã¯ããã®ã¡ã½ããã®å½¹å²ã§ã¯ãªãããããã¾ããããããããã¨ããã®ã¡ã½ããã Customer
ã¯ã©ã¹ã®ã¯ã©ã¹ã¡ã½ããã¨ãã¦å®è£
ããã®ã¯ééãã ã£ãã®ããããã¾ããã
次åã¯ããããã£ã観ç¹ã§ãªãã¡ã¯ã¿ãªã³ã°ã«ããè¨è¨ã®æ¹åã試ã¿ã¾ããã§ã¯ãã¾ãã