代码之家  ›  专栏  ›  技术社区  ›  Richie Thomas

Protobuf相关的单元测试在我的本地机器上通过,但在Jenkins管道中失败

  •  1
  • Richie Thomas  · 技术社区  · 6 年前

    我在Rails应用程序中有一组序列化器对象的单元测试。这些序列化程序对象使用 google-protobuf (~> 3.5) gem,包括 Google::Protobuf::Timestamp 对象对于与时间相关的属性(如 purchase_order#created_at ,则, line_item#created_at inspection_event#event_occured_at ),我们使用一个TimeSerializer对象,实现如下:

    # frozen_string_literal: true
    
    module ProtoSerializers
      class TimeSerializer < BaseProtoSerializer
        def serialize
          return if object.nil?
    
          GOOGLE_BASE::Timestamp.new(seconds: object&.to_i, nanos: object&.nsec)
        end
      end
    end
    

    这是通过调用 ProtoSerializers::TimeSerializer.serialize(time) 哪里 time 是Rails时间或日期时间对象。

    测试将序列化的预期结果与实际结果进行比较,如果结果匹配,则通过,否则失败:

    describe '#serialize an inspection whose purchase order and line item are both archived' do
    
      subject { described_class.serialize(object) }
    
      let(:purchase_order) { create(:purchase_order, :is_archived) }
      let(:line_item) { create(:line_item, :archived, purchase_order: purchase_order) }
      let(:object) { create(:inspection, line_item: line_item) }
    
      it 'serializes attributes' do
        expect(subject).to be_a(MyCorp::Proto::MyApp::InspectionEvent)
    
        expect(subject).to have_attributes(
          ...(misc key-value pairs)...
          purchase_order: ProtoSerializers::PurchaseOrderSerializer.serialize(purchase_order),
          line_item: ProtoSerializers::LineItemSerializer.serialize(line_item),
          event_occurred_at: ProtoSerializers::TimeSerializer.serialize(object.event_occurred_at)
        )
      end
    end
    

    这个 PurchaseOrder LineItem 两种型号都有 created_at 属性,根据标准Rails实践。

    该测试在我的机器上通过,但当我将其推到Github(启动Jenkins测试管道)时失败。预期与实际差异如下所示:

    20:00:39        -:line_item => <MyCorp::Proto::MyApp::LineItem: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710602>, ...>,
    20:00:39        +:line_item => <MyCorp::Proto::MyApp::LineItem: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710000>, ...>,
    20:00:39        -:purchase_order => <MyCorp::Proto::MyApp::PurchaseOrder: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710602>>,
    20:00:39        +:purchase_order => <MyCorp::Proto::MyApp::PurchaseOrder: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710000>>,
    

    如您所见 seconds 属性匹配,但 nanos attrivute关闭了几百纳秒。我已经尝试在这个测试中使用Timecop,如下所示,但失败的测试仍然存在:

    before { Timecop.freeze(Time.now) }
    
    after { Timecop.return }
    

    我不确定Jenkins管道和我的机器之间有什么不同。我使用的是带有Intel Core i7处理器的Macbook,我认为它是64位的。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Richie Thomas    6 年前

    原因似乎是在我的机器(带有Intel Core i7处理器的Macbook)上将64位整数转换为Protobufs 32位整数纳秒时,精度降低。为了解决这个问题,我不得不把时间模拟成精度损失不是一个因素的东西。最后,我使用了Epoch时间,如下所示:

    before { Timecop.freeze(Time.at(0)) }
    
    after { Timecop.return }
    

    这就解决了问题。