【问题标题】:Rspec testing inside a loop循环内的 Rspec 测试
【发布时间】:2016-07-10 11:09:34
【问题描述】:

我正在尝试在循环中测试代码,我该怎么做:

class MyClass
  def initialize(topics, env, config, limit)
    @client = Twitter::Streaming::Client.new(config)
    @topics = topics
    @env = env
    @limit = limit
  end

 def start
   @client.filter(track: @topics.join(",")) do |object|
   # how would I test the code inside here, basically logical stuff
    next if !object.is_a?(Twitter::Tweet)

    txt = get_txt(object.text)
  end
end

有没有办法做到这一点?

【问题讨论】:

  • 我认为您不测试块内的代码。相反,您将测试该方法的返回值是否符合预期。因为从理论上讲,您并不关心该方法是作为循环实现的,还是使用迭代器实现的,或者它是否使用数据库来解决问题。那么您希望您的 start 方法返回什么?
  • 没什么,因为它是一个流媒体服务,我正在关注某些逻辑,如果不是,则进入下一个迭代。老实说,几乎是无限循环:) 当然,还有一些数据库操作。如何改变这一点,使其可测试。其实,我也想过要崩溃再回来,但后来使用next变得很痛苦:(

标签: ruby-on-rails ruby unit-testing rspec


【解决方案1】:

如果您认为您可以使用Twitter::Streaming::Client 中的double,该Twitter::Streaming::Client 具有方法filter,并且当调用此方法时,它会返回所需的输出:

let(:client) { double 'Twitter Client', filter: twitters }

您将需要手动构建twitters 对象(抱歉,我缺乏上下文,但我从未使用过 Twitter 客户端),然后您可以对start 方法的结果进行断言。

【讨论】:

    【解决方案2】:

    如您所见,测试该代码非常棘手。这是因为对 Twitter 客户端 gem 的依赖。

    你可以走几条路:

    1. 不要测试它 - Twitter 客户端 gem 应该为您提供 Twitter::Tweet 对象。你只测试你的逻辑,即get_txt方法

    2. 按照@Marcus Gomes 所说的去做 - 创建一个集合替身,并实现了filter 方法。

    3. 我更愿意做的是在规范中存根 @client.filter 调用。

    例如,在您的规范中:

    some_collection_of_tweets = [
      double(Twitter::Tweet, text: "I'll be back!"),
      double(Twitter::Tweet, text: "I dare ya, I double dare ya!")
    ]
    @my_class = MyClass.new(topics, env, config, limit)
    allow(@my_class.client).to receive(:filter).and_return(some_collection_of_tweets)
    

    这意味着每次类调用@client.filter 时都会返回some_collection_of_tweets 集合,并且通过由您构建数据,您可以设置什么期望。

    您必须更改的一件事是在类上设置attr_reader :client。此类测试的唯一副作用是您将代码绑定到 Twitter 客户端的接口。

    但就像其他一切一样......权衡:)

    希望有帮助!

    【讨论】:

      【解决方案3】:

      如果你真的想测试你的无限循环逻辑,也许你可以这样做?

      RSpec.describe MyClass do
        subject { MyClass.new(['foo','bar'], 'test', 'config', 1) }
      
        let(:streaming_client) { Twitter::Streaming::Client.new }
      
        describe '#start' do
          let(:valid_tweet) { Twitter::Tweet.new(id: 1) }
      
          before do
            allow(Twitter::Streaming::Client).to receive(:new)
              .with('config').and_return(streaming_client)
          end
      
          after { subject.start }
      
          it '#get_txt receives valid tweets only' do
            allow(valid_tweet).to receive(:text)
              .and_return('Valid Tweet')
      
            allow(streaming_client).to receive(:filter)
              .with(track: 'foo,bar')
              .and_yield(valid_tweet)
      
            expect(subject).to receive(:get_txt)
              .with('Valid Tweet')
          end
      
          it '#get_txt does not receive invalid tweets' do
            allow(streaming_client).to receive(:filter)
              .with(track: 'foo,bar')
              .and_yield('Invalid Tweet')
      
            expect(subject).not_to receive(:get_txt)
          end
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-02
        • 1970-01-01
        • 2014-02-07
        • 1970-01-01
        • 2017-08-01
        • 1970-01-01
        • 2011-06-28
        相关资源
        最近更新 更多