【问题标题】:Structuring a CSV data driven test with RSpec the basic simple way?使用 RSpec 构建 CSV 数据驱动测试的基本简单方法?
【发布时间】:2015-07-13 03:41:01
【问题描述】:

我是 Ruby 和 RSpec 的新手,做了一些研究,发现有几种方法可以从在线帖子中进行数据驱动的枚举测试,但它们不像完整的教程那样深入细节。因此,在我再次详细查看那些在线文章之前,我想先在这里问一下。

这是我基于使用 RSpec 的标准简单方法的设置(定义了 describe & it 块,不导入 RSpec 的部分来只做预期)。然后我尝试为其添加数据驱动能力:

require 'rspec'
require 'csv'

describe "test suite name" do
  before :all do
    #this CSV mapping method found online...
    @device_client = CSV.read path
    @descriptor = @device_client.shift
    @descriptor = @descriptor.map { |key| key.to_sym }
    @device_client.map { |client| Hash[ @descriptor.zip(client) ] }
  end

  @device_client.each do |client|
    describe "#{client[:test_scenario]}" do
      if "match some CSV field value"
        it "should run this kind of test" do
          #additional code as needed
          expect(some_actual).to eql(some_expected)
        end
      end

      if "match some other CSV field value"
        it "should run that kind of test" do
          #additional code as needed
          expect(some_actual).to eql(some_expected)
        end
      end

      it "some other test common to all CSV rows" do
        #stuff
      end
    end
  end

end

我在这里注意到的是,@device_client 是 nil,因为它现在是结构化的(使用“p @device_client”语句调试以转储内容)。为了使其具有价值,我必须将散列包含在它在范围内的 it 块中(我通常将它放在另一个描述块中,但假设我可以跳过额外的描述)。

我如何重组测试以“读取”相同的内容(对测试的读者)并按照我想要的方式运行?如果重组意味着我不能使用标准的 RSpec 格式并且必须以不同的方式要求 RSpec 组件,那很好(网上的帖子似乎没有遵循简单/基本的 RSpec 格式)。

我认为我的代码解释起来相当简单。如果不是,目的是使用 CSV 输入来动态构建测试。每个 CSV 行是一个具有多个测试的场景 - 1 个测试根据 CSV 字段值而有所不同,因此 ifs,其余测试对所有场景都是通用的。我们对文件中的尽可能多的 CSV 场景行重复此设置。而 before all 块是我们处理 CSV 数据之前的全局设置。

在重组中,理想情况下,我希望保留 describe & it 文本描述块(或与其等效的部分),以便在测试结果中显示它们描述测试,而不仅仅是一堆期望。

【问题讨论】:

    标签: rspec rspec2 rspec3


    【解决方案1】:

    这样的事情应该可以工作:

    require 'csv'
    
    describe "test suite name" do
      device_client = CSV.read path
      descriptor = device_client.shift
      descriptor = descriptor.map { |key| key.to_sym }
      clients = device_client.map { |client| Hash[ descriptor.zip(client) ] }
    
      clients.each do |client|
        describe "#{client[:test_scenario]}" do
          if "match some CSV field value"
            it "should run this kind of test" do
              #additional code as needed
              expect(some_actual).to eql(some_expected)
            end
          end
    
          if "match some other CSV field value"
            it "should run that kind of test" do
              #additional code as needed
              expect(some_actual).to eql(some_expected)
            end
          end
    
          it "some other test common to all CSV rows" do
            #stuff
          end
        end
      end
    end
    

    与您的版本相比的显着变化:

    • 不需要rspec(当您运行rspec 命令时,RSpec 会自行加载)。
    • 我将 CSV 逻辑从 before(:all) 移出到 describe 正文中。您之前遇到的问题是 before 钩子在所有示例和组定义之后运行,就在执行特定组之前。您需要在规范定义期间利用 CSV 文件内容(在此期间执行 describe 块)。
    • 我从实例变量切换到局部变量。您之前所做的不起作用,因为 before(:all) 钩子在示例组类的实例的上下文中运行,而 describe 块在类本身的上下文中运行 - 所以它们在不同的上下文中运行并且不要'无权访问相同的实例变量。一旦我们将逻辑移到 describe 块中,您就可以使用简单的局部变量。
    • 我在before(:all) 逻辑的最后一行添加了clients =。您之前所做的是丢弃 device_client.map { ... } 的结果,但我假设这就是您想要使用的。

    有关describebefore 块之间范围差异的更多信息,请参阅section in the rspec-core README that discusses scope

    【讨论】:

    • 感谢您的解决方案和有见地的信息。
    猜你喜欢
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多