2015-07-24 12 views
16

Tôi có một phương thức sử dụng DateTime.now để thực hiện tìm kiếm trên một số dữ liệu, tôi muốn kiểm tra phương thức với các ngày khác nhau nhưng tôi không biết cách làm sao DateTime. bây giờ tôi cũng không thể làm cho nó hoạt động với Timecop (nếu nó hoạt động như thế).Rails - Thử nghiệm một phương thức sử dụng DateTime.now

Với thời gian cảnh sát tôi đã cố gắng

it 'has the correct amount if falls in the previous month' do 
     t = "25 May".to_datetime 
     Timecop.travel(t) 
     puts DateTime.now 

     expect(@employee.monthly_sales).to eq 150 
end 

khi tôi chạy spec tôi có thể thấy rằng đặt DateTime.now cho 2015-05-25T01:00:00+01:00 nhưng có puts cùng DateTime.now trong phương pháp Tôi đang thử nghiệm kết quả đầu ra 2015-07-24T08:57:53+01:00 (ngày nay ngày). Làm cách nào tôi có thể thực hiện việc này?

------------------ cập nhật --------------------------- ------------------------

Tôi đã thiết lập hồ sơ (@employee, v.v.) trong khối before(:all) dường như đã gây ra vấn đề. Nó chỉ hoạt động khi thiết lập được thực hiện sau khối Timecop do. Tại sao điều này là trường hợp?

+0

Mã của bạn nên hoạt động (chỉ cần nhớ gọi 'Timecop.return' khi bạn hoàn tất). Bạn có thể dán phần thân của phương thức 'monthly_sales' được không? – tompave

+0

phương pháp không liên quan khác với phương thức gọi DateTime.now –

+0

Sau đó, tôi sợ rằng tôi không thể giúp bạn. – tompave

Trả lời

8

TL; DR: Vấn đề là DateTime.now được gọi trong số Employee trước khi Timecop.freeze được gọi trong thông số kỹ thuật.

Timecop giả lập hàm tạo của Time, DateDateTime. Bất kỳ phiên bản nào được tạo giữa freezereturn (hoặc bên trong khối freeze) sẽ được chế nhạo.
Mọi trường hợp được tạo trước freeze hoặc sau return sẽ không bị ảnh hưởng vì Timecop không gây rối với các đối tượng hiện có.

Từ README (tôi nhấn mạnh):

Một viên ngọc cung cấp "thời gian đi lại" và "thời gian đóng băng" khả năng, làm cho nó chết đơn giản để kiểm tra mã phụ thuộc thời gian. Nó cung cấp một phương thức thống nhất để giả lập Time.now, Date.today và DateTime.now trong một cuộc gọi duy nhất.

Vì vậy, nó là điều cần thiết để gọi Timecop.freeze trước khi bạn tạo đối tượng Time bạn muốn thử. Nếu bạn freeze trong khối RSpec before, điều này sẽ được chạy trước subject được đánh giá. Tuy nhiên, nếu bạn có một khối before nơi bạn thiết lập chủ thể của mình (@employee trong trường hợp của bạn), và có một khối before khác trong lồng nhau describe thì chủ đề của bạn đã được thiết lập, gọi là DateTime.new trước khi bạn đóng băng thời gian.


gì sẽ xảy ra nếu bạn thêm dòng sau vào Employee

class Employee 
    def now 
    DateTime.now 
    end 
end 

Sau đó, bạn chạy spec sau:

describe '#now' do 
    let(:employee) { @employee } 
    it 'has the correct amount if falls in the previous month', focus: true do 
    t = "25 May".to_datetime 
    Timecop.freeze(t) do 
     expect(DateTime.now).to eq t 
     expect(employee.now).to eq t 

     expect(employee.now.class).to be DateTime 
     expect(employee.now.class.object_id).to be DateTime.object_id 
    end 
    end 
end 

Thay vì sử dụng một khối freeze, bạn cũng có thể freezereturn trong rspec beforeafter móc:

describe Employee do 
    let(:frozen_time) { "25 May".to_datetime } 
    before { Timecop.freeze(frozen_time) } 
    after { Timecop.return } 
    subject { FactoryGirl.create :employee } 

    it 'has the correct amount if falls in the previous month' do 
    # spec here 
    end 

end 

Off-topic, nhưng có lẽ có một cái nhìn tại http://betterspecs.org/

+0

thông số này vượt qua –

+0

Nếu 'mong đợi (employee.now) .to eq t' vượt qua thì Timecop hoạt động bình thường. Bạn đã thử spec của bạn bên trong một khối 'Timecop.freeze'? – amiuhle

+0

nó hoạt động bên trong khối đóng băng nhưng chỉ khi dữ liệu được thiết lập bên trong nó –

3

Timecop sẽ có thể xử lý những gì bạn muốn. Cố gắng đóng băng thời gian trước khi chạy thử nghiệm của bạn thay vì chỉ đi du lịch, sau đó unfreeze khi bạn hoàn thành. Như thế này:

before do 
    t = "25 May".to_datetime 
    Timecop.freeze(t) 
end 

after do 
    Timecop.return 
end 

it 'has the correct amount if falls in the previous month' do 
    puts DateTime.now 
    expect(@employee.monthly_sales).to eq 150 
end 

Từ readme Timecop của:

đóng băng được sử dụng để tĩnh nhạo báng các khái niệm về ngay bây giờ. Khi chương trình của bạn thực hiện, Time.now sẽ không thay đổi trừ khi bạn thực hiện các cuộc gọi tiếp theo vào API Timecop. Mặt khác, ngược lại, tính toán một sự bù đắp giữa những gì chúng ta đang nghĩ Time.now là (nhớ lại rằng chúng ta hỗ trợ di chuyển lồng nhau) và thời gian trôi qua. Nó sử dụng bù đắp này để mô phỏng thời gian trôi qua.

Vì vậy, bạn muốn đóng băng thời gian tại một địa điểm nhất định, thay vì chỉ đi đến thời điểm đó. Vì thời gian sẽ trôi qua với một chuyến đi như bình thường, nhưng từ một điểm xuất phát khác.

Nếu điều này vẫn không làm việc, bạn có thể đặt lời gọi phương thức của bạn trong một khối với Timecop để đảm bảo rằng nó được đóng băng thời gian bên trong các khối như:

t = "25 May".to_datetime 
Timecop.travel(t) do # Or use freeze here, depending on what you need 
    puts DateTime.now 
    expect(@employee.monthly_sales).to eq 150 
end 
+0

cả hai điều này vẫn không thành công –

0

tôi chạy vào một số vấn đề với Timecop và các công cụ ma thuật khác mà messes với Ngày, Thời gian và DateTime lớp học và phương pháp của họ. Tôi thấy rằng nó là tốt hơn để chỉ sử dụng dependency injection thay vì:

đang Nhân viên

class Employee 
    def monthly_sales(for_date = nil) 
    for_date ||= DateTime.now 

    # now calculate sales for 'for_date', instead of current month 
    end 
end 

Spec

it 'has the correct amount if falls in the previous month' do 
    t = "25 May".to_datetime 
    expect(@employee.monthly_sales(t)).to eq 150 
end 

Chúng tôi, những người của thế giới Ruby, tìm niềm vui lớn trong sử dụng một số thủ thuật ma thuật, những người đang sử dụng các ngôn ngữ lập trình ít diễn đạt hơn thì không thể sử dụng được. Nhưng đây là trường hợp phép thuật quá tối và thực sự nên tránh. Chỉ cần sử dụng phương pháp thực hành tốt nhất được chấp nhận phổ biến của tiêm phụ thuộc thay thế.

Các vấn đề liên quan