আরএসপেকের সাথে সময়ের তুলনায় সমস্যা


119

আমি রুবেলগুলিকে রেল 4 এবং আরএসপেক-রেলস রত্ন 2.14 ব্যবহার করছি। আমার কোনও অবজেক্টের জন্য আমি updated_atএকটি নিয়ামক ক্রিয়াকলাপ চালানোর পরে অবজেক্ট অ্যাট্রিবিউটের সাথে বর্তমান সময়ের তুলনা করতে চাই , তবে চশমাটি পাস না হওয়ায় আমি সমস্যায় আছি। এটি হল, নিম্নলিখিতটি কোডের নীচে দেওয়া হল:

it "updates updated_at attribute" do
  Timecop.freeze

  patch :update
  @article.reload
  expect(@article.updated_at).to eq(Time.now)
end

যখন আমি উপরের অনুমানটি চালাই আমি নিম্নলিখিত ত্রুটিটি পাই:

Failure/Error: expect(@article.updated_at).to eq(Time.now)

   expected: 2013-12-05 14:42:20 UTC
        got: Thu, 05 Dec 2013 08:42:20 CST -06:00

   (compared using ==)

আমি কিভাবে অনুমানটি পাস করতে পারি?


দ্রষ্টব্য : আমি নিম্নলিখিতগুলিও চেষ্টা করেছি ( utcসংযোজনটি দ্রষ্টব্য ):

it "updates updated_at attribute" do
  Timecop.freeze

  patch :update
  @article.reload
  expect(@article.updated_at.utc).to eq(Time.now)
end

তবে অনুমানটি এখনও পাস হয় না ("পাওয়া" মানের পার্থক্যটি নোট করুন):

Failure/Error: expect(@article.updated_at.utc).to eq(Time.now)

   expected: 2013-12-05 14:42:20 UTC
        got: 2013-12-05 14:42:20 UTC

   (compared using ==)

এটি অবজেক্ট আইডির তুলনা করছে, সুতরাং পরিদর্শন থেকে প্রাপ্ত পাঠ্যটি মিলছে, তবে নীচে আপনার দুটি পৃথক সময় অবজেক্ট রয়েছে। আপনি কেবল ব্যবহার করতে পারেন ===, তবে এটি দ্বিতীয় সীমানা অতিক্রম করে ভুগতে পারে। সম্ভবত আপনার নিজের ম্যাচারের সন্ধান বা লেখাই সম্ভবত সেরা, যাতে আপনি যুগের সেকেন্ডে রূপান্তর করেন এবং একটি সামান্য পরম পার্থক্যের জন্য অনুমতি দেন।
নিল স্লেটার

যদি আমি আপনাকে "দ্বিতীয় সীমানা অতিক্রম" সম্পর্কিত বুঝতে পারি তবে সমস্যাটি উত্থাপিত হবে না যেহেতু আমি টাইমকপ রত্নটি ব্যবহার করছি যা সময়টিকে "জমে যায়"।
ব্যাকো

আহ আমি মিস করেছি, দুঃখিত। কোন ক্ষেত্রে, ===পরিবর্তে কেবল ব্যবহার করুন ==- বর্তমানে আপনি দুটি ভিন্ন টাইম অবজেক্টের অবজেক্ট_আইডি তুলনা করছেন। যদিও টাইমকপ ডাটাবেস সার্ভারের সময় হিমায়িত করবে না। । । সুতরাং যদি আপনার টাইমস্ট্যাম্পগুলি আরডিবিএমএস দ্বারা উত্পাদিত হয় তবে এটি কার্যকর হবে না (আমি আশা করি এটি আপনার পক্ষে যদিও এখানে সমস্যা নয়)
নিল স্লেটার

উত্তর:


156

রুবি টাইম অবজেক্ট ডাটাবেসের চেয়ে বৃহত্তর নির্ভুলতা বজায় রাখে। মানটি যখন ডাটাবেস থেকে ফিরে পঠিত হয় তখন এটি কেবল মাইক্রোসেকেন্ড নির্ভুলতায় সংরক্ষণ করা হয়, যখন ইন-মেমরির উপস্থাপনটি ন্যানোসেকেন্ডগুলিতে যথাযথ হয়।

যদি আপনি মিলিসেকেন্ডের পার্থক্যের বিষয়ে চিন্তা না করেন তবে আপনি আপনার প্রত্যাশার উভয় পক্ষেই একটি_স / টু_আই করতে পারেন

expect(@article.updated_at.utc.to_s).to eq(Time.now.to_s)

অথবা

expect(@article.updated_at.utc.to_i).to eq(Time.now.to_i)

পড়ুন এই কেন বার ভিন্ন আরও তথ্যের জন্য


আপনি প্রশ্নটি থেকে Timecopকোডটিতে দেখতে পারেন, আমি রত্নটি ব্যবহার করি । এটি কি সময়কে "হিমায়িত" করে সমস্যার সমাধান করা উচিত?
ব্যাকো

আপনি ডেটাবেজে সময় সাশ্রয় করে এটিকে পুনরুদ্ধার করুন (@ আর্টিকেল.আপডেটেড্যাট) যা এটি ন্যানোসেকেন্ডগুলি আলগা করে তোলে যেখানে টাইম.নো ন্যানোসেকেন্ডটিকে ধরে রেখেছে। এটি আমার উত্তরের প্রথম কয়েকটি লাইন থেকে পরিষ্কার হওয়া উচিত
উষা

3
গৃহীত উত্তর নীচের উত্তরের চেয়ে প্রায় এক বছরের পুরনো - be_within ম্যাচার এটি পরিচালনা করার একটি আরও ভাল উপায়: ক) আপনার কোনও রত্নের দরকার নেই; খ) এটি যে কোনও ধরণের মান (পূর্ণসংখ্যা, ভাসা, তারিখ, সময়, ইত্যাদি) জন্য কাজ করে; গ) এটি স্থানীয়ভাবে
আরএসপেকের

3
এটি একটি "ঠিক আছে" সমাধান, তবে অবশ্যই be_withinএটি সঠিক
ফ্রান্সেস্কো বেলাদোনা

হ্যালো আমি ডেটটাইম তুলনাগুলি চাকরি সঞ্চারিত বিলম্ব প্রত্যাশার সাথে ব্যবহার expect {FooJob.perform_now}.to have_enqueued_job(FooJob).at(some_time) করছি আমি নিশ্চিত নই যে .atম্যাচার .to_iএই সমস্যার মুখোমুখি হয়ে কারও সাথে পূর্ণসংখ্যায় রূপান্তরিত সময়টিকে গ্রহণ করবে ?
সিরিল ডুচন-ডরিস

200

আমি be_withinডিফল্ট আরএসপেক ম্যাচারটি আরও মার্জিত ব্যবহার করে দেখতে পেলাম :

expect(@article.updated_at.utc).to be_within(1.second).of Time.now

2
.000001 গুলি কিছুটা টাইট। আমি এমনকি .001 চেষ্টা করেছিলাম এবং এটি কখনও কখনও ব্যর্থ হয়। এমনকি .1 সেকেন্ডের মধ্যে আমার মনে হয় যে সময়টি এখন সেট করা হচ্ছে। আমার উদ্দেশ্যে যথেষ্ট ভাল।
স্মোকথ

3
আমি মনে করি এই উত্তরটি আরও ভাল কারণ এটি কিছু সম্পর্কিত সম্পর্কযুক্ত পদ্ধতির পিছনে অস্পষ্ট না করে পরীক্ষার অভিপ্রায় প্রকাশ করে to_s। এছাড়াও, to_iএবং to_sসময়টি সেকেন্ডের শেষের কাছাকাছি থাকলে খুব কমই ব্যর্থ হতে পারে।
বি সাত

2
দেখে মনে হচ্ছে be_withinম্যাচারটি আরএসপেক ২.১.০-এ to ই নভেম্বর, ২০১০ এ যুক্ত হয়েছিল এবং তার পর থেকে কয়েকগুণ উন্নত হয়েছে। rspec.info/docamentation/2.14/rspec-expectations/…
মার্ক বেরি

1
আমি পেতে undefined method 'second' for 1:Fixnum। আমার কিছু দরকার আছে require?
ডেভিড মোলস

3
@ ডেভিডমোলস .secondএকটি রেল সম্প্রসারণ: api.rubyonrails.org/classes/Numeric.html
জাওয়াদস্যাক

10

হ্যাঁ ম্যাচারের Oinপরামর্শ দিচ্ছেন be_withinএটি সর্বোত্তম অনুশীলন

... এবং এটিতে আরও কিছু ইউএসকেস রয়েছে -> http://www.eq8.eu/blogs/27-rspec-be_within-matcher

তবে এর সাথে কীভাবে মোকাবিলা করবেন তার আরও একটি উপায় হ'ল রেলগুলি অন্তর্নির্মিত middayএবং middnightবৈশিষ্ট্যগুলি ব্যবহার করা।

it do
  # ...
  stubtime = Time.now.midday
  expect(Time).to receive(:now).and_return(stubtime)

  patch :update 
  expect(@article.reload.updated_at).to eq(stubtime)
  # ...
end

এখন এটি কেবল প্রদর্শনের জন্য!

আপনি এটি সমস্ত টাইম স্ট্যাবিং করায় আমি এটি একটি নিয়ামক হিসাবে ব্যবহার করব না w নতুন কল => সর্বকালের বৈশিষ্ট্যের একই সময় থাকবে => আপনি যে ধারণাটি অর্জন করার চেষ্টা করছেন তা প্রমাণ করতে পারে না। আমি সাধারণত এটির অনুরূপ রচিত রুবি অবজেক্টে এটি ব্যবহার করি:

class MyService
  attr_reader :time_evaluator, resource

  def initialize(resource:, time_evaluator: ->{Time.now})
    @time_evaluator = time_evaluator
    @resource = resource
  end

  def call
    # do some complex logic
    resource.published_at = time_evaluator.call
  end
end

require 'rspec'
require 'active_support/time'
require 'ostruct'

RSpec.describe MyService do
  let(:service) { described_class.new(resource: resource, time_evaluator: -> { Time.now.midday } ) }
  let(:resource) { OpenStruct.new }

  it do
    service.call
    expect(resource.published_at).to eq(Time.now.midday)    
  end
end

তবে সত্যই আমি be_withinটাইম.নো.মিডডির সাথে তুলনা করার সময় ম্যাচারের সাথে লেগে থাকার পরামর্শ দিই!

সুতরাং হ্যাঁ be_withinপ্লাস ম্যাচারের সাথে স্টিক করুন ;)


আপডেট 2017-02

মন্তব্যে প্রশ্ন:

সময় যদি একটি হ্যাশ হয়? প্রত্যাশার যে কোনও উপায়ে (hash_1) .to eq (hash_2) কাজ যখন কিছু hash_1 মান প্রাক db- বার হয় এবং hash_2 এর সাথে সম্পর্কিত মানগুলি পোস্ট db- বার হয়? -

expect({mytime: Time.now}).to match({mytime: be_within(3.seconds).of(Time.now)}) `

আপনি ম্যাচারে কোনও আরএসপেক ম্যাচার পাস করতে পারেন match(উদাহরণস্বরূপ আপনি খাঁটি আরএসপেক দিয়ে এপিআই টেস্টিংও করতে পারেন )

"পোস্ট-ডিবি-বার" হিসাবে আমি অনুমান করি আপনি ডিবিতে সংরক্ষণের পরে উত্পন্ন স্ট্রিংটি বোঝাচ্ছেন। আমি এই কেসটিকে 2 প্রত্যাশার সাথে ডিকুয়াল করার পরামর্শ দেব (একটি হ্যাশ স্ট্রাকচার নিশ্চিত করে, দ্বিতীয় সময়টি যাচাই করে) তাই আপনি কিছু করতে পারেন:

hash = {mytime: Time.now.to_s(:db)}
expect(hash).to match({mytime: be_kind_of(String))
expect(Time.parse(hash.fetch(:mytime))).to be_within(3.seconds).of(Time.now)

তবে যদি এই ক্ষেত্রে আপনার পরীক্ষার স্যুটে প্রায়শই থাকে তবে আমি আপনার নিজের আরএসপেক ম্যাচার (যেমন be_near_time_now_db_string) ডিবি স্ট্রিংয়ের সময়কে টাইম অবজেক্টে রূপান্তর করার পরামর্শ দিচ্ছি এবং তারপরে এটির অংশ হিসাবে ব্যবহার করুন match(hash):

 expect(hash).to match({mytime: be_near_time_now_db_string})  # you need to write your own matcher for this to work.

সময় যদি একটি হ্যাশ হয়? expect(hash_1).to eq(hash_2)কাজ করার কোনও উপায় যখন কিছু হ্যাশ_1 মান পূর্ব-ডিবি-বার হয় এবং হ্যাশ 3 এর সাথে সম্পর্কিত মানগুলি পোস্ট-ডিবি-বার হয়?
মাইকেল জনস্টন

আমি ভাবছিলাম একটি স্বেচ্ছাচারী হ্যাশ (আমার অনুমানটি জোর দিয়ে বলছে যে কোনও অপারেশন মোটেও রেকর্ড পরিবর্তন করে না)। কিন্তু ধন্যবাদ!
মাইকেল জনস্টন

10

পুরানো পোস্ট, তবে আমি আশা করি যে এটি সমাধানের জন্য এখানে প্রবেশকারী যে কোনও ব্যক্তিকে সহায়তা করবে। আমি মনে করি কেবল ম্যানুয়ালি তারিখটি তৈরি করা সহজ এবং আরও নির্ভরযোগ্য:

it "updates updated_at attribute" do
  freezed_time = Time.utc(2015, 1, 1, 12, 0, 0) #Put here any time you want
  Timecop.freeze(freezed_time) do
    patch :update
    @article.reload
    expect(@article.updated_at).to eq(freezed_time)
  end
end

to_xদশমিকের বিষয়ে বা চিন্তা না করেই সঞ্চিত তারিখটি সঠিক তা নিশ্চিত করে ures


নিশ্চিত হয়ে নিন যে আপনি
অনুমানের

পরিবর্তে এটি একটি ব্লক ব্যবহার করতে পরিবর্তন করা হয়েছে। এইভাবে আপনি স্বাভাবিক সময়ে ফিরতে ভুলবেন না।
jBilbo

8

আপনি তারিখ / তারিখ / সময় অবজেক্টটিকে স্ট্রিংতে রূপান্তর করতে পারেন যেমন এটি ডাটাবেসে সঞ্চিত রয়েছে to_s(:db)

expect(@article.updated_at.to_s(:db)).to eq '2015-01-01 00:00:00'
expect(@article.updated_at.to_s(:db)).to eq Time.current.to_s(:db)

7

এই সমস্যাটির আশেপাশে সবচেয়ে সহজ উপায়টি হ'ল এর current_timeমতো একটি পরীক্ষার সহায়ক পদ্ধতি তৈরি করা:

module SpecHelpers
  # Database time rounds to the nearest millisecond, so for comparison its
  # easiest to use this method instead
  def current_time
    Time.zone.now.change(usec: 0)
  end
end

RSpec.configure do |config|
  config.include SpecHelpers
end

এখন সময়টি সর্বদা নিকটতম মিলিসেকেন্ডের সাথে তুলনা করার জন্য সরাসরি হয়:

it "updates updated_at attribute" do
  Timecop.freeze(current_time)

  patch :update
  @article.reload
  expect(@article.updated_at).to eq(current_time)
end

1
.change(usec: 0)খুব সহায়ক
কোয়েন

2
আমরা .change(usec: 0)কোনও নির্দিষ্ট সহায়ককেও ব্যবহার না করেই সমস্যাটি সমাধান করতে এই কৌশলটি ব্যবহার করতে পারি । প্রথম লাইনটি যদি হয় Timecop.freeze(Time.current.change(usec: 0))তবে আমরা .to eq(Time.now)শেষে শেষে তুলনা করতে পারি ।
হ্যারি উড

0

যেহেতু আমি হ্যাশগুলির সাথে তুলনা করছিলাম, এই সমাধানগুলির বেশিরভাগটি আমার পক্ষে কাজ করে নি তাই আমি খুঁজে পেলাম যে সহজ সমাধানটি আমি তুলনা করছিলাম এমন হ্যাশ থেকে ডেটা ধরা। যেহেতু আপডেট_আউট সময়গুলি আমার পক্ষে এই কাজটি ভাল করে তা পরীক্ষা করার জন্য আসলে কার্যকর হয় না।

data = { updated_at: Date.new(2019, 1, 1,), some_other_keys: ...}

expect(data).to eq(
  {updated_at: data[:updated_at], some_other_keys: ...}
)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.