Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rspec:如何测试ActiveRecord::Base.connection.execute_Ruby On Rails_Ruby_Activerecord_Rspec - Fatal编程技术网

Ruby on rails Rspec:如何测试ActiveRecord::Base.connection.execute

Ruby on rails Rspec:如何测试ActiveRecord::Base.connection.execute,ruby-on-rails,ruby,activerecord,rspec,Ruby On Rails,Ruby,Activerecord,Rspec,我正在使用原始/裸机sql插入来提高服务的写入性能。我的模块里有类似的东西- insert = "('#{id}', '#{status}', '#{some_time_val}')" sql_string = "INSERT INTO history ('device_id', 'status', 'time') VALUES #{insert}" ActiveRecord::Base.connection.execute sql_string 当我编写下面这样的rspec时,它会测试所有内

我正在使用原始/裸机sql插入来提高服务的写入性能。我的模块里有类似的东西-

insert = "('#{id}', '#{status}', '#{some_time_val}')"
sql_string = "INSERT INTO history ('device_id', 'status', 'time') VALUES #{insert}"
ActiveRecord::Base.connection.execute sql_string
当我编写下面这样的rspec时,它会测试所有内容,除了插入是否成功。因此,由于rspec、数据库清理器等执行回滚和事务的方式,我的期望永远不会起作用。 我试着用

  self.use_transactional_fixtures = false

但是这些插入仍然没有进入我的测试数据库

describe Worker do
  let (:device1) {FactoryGirl.create(:device)}
  let (:device2) {FactoryGirl.create(:device)}
  let (:device3) {FactoryGirl.create(:device)}
  self.use_transactional_fixtures = false

  before(:all) do
    DatabaseCleaner.strategy = nil
  end

  it "does something" do
    devices = [{"status" => "Offline", "time" => "2013-09-17 18:17:17", "id" => device1.id},
                {"status" => "Online", "time" => "2013-09-17 18:18:18", "id" => device2.id}]
    Worker.any_instance.stubs(:devices).returns(devices) ## Not important for this question
    Worker.new.perform

    device1.reload.status.should == "Offline" # FAILS
  end

end

我如何测试这个?像这样测试原始sql插入的好策略是什么?

关于如何正确测试代码,有两种观点:“方法”观点是为了确保您自己的行为正确,而“结果”观点则倾向于检查结果。我将提供这两种观点

方法:

您没有编写ActiveRecord::Base.connection.execute,您不对它的正常工作负责。然后,您的测试可以关注您传递给execute方法的内容。那么,一个匹配的规范可能看起来像这样

connection = double("Connection")
expect(ActiveRecord::Base).to receive(:connection) { connection }
expect(connection).to receive(:execute).with("...")
Worker.new.perform
在哪里。。。是要生成的SQL。根据您的喜好,验证SQL是否正常工作可以在其他地方进行,也可以根本不进行。这可以确保您和未来的开发人员将正确的指令传递到数据库中

结果:

这种方法在所采取的方法中找不到保证,它在结果中找到了保证。这就是您在上述示例中采用的方法

您没有向我们展示上面的perform方法是什么样子的,因此我们不确定您的实现代码是否存在问题,而不是您用来提示ActiveRecord注意您的更改的重载机制。ActiveRecord有多种性能增强功能,旨在云计算数据库内容与Ruby VM对象图中能够访问的内容之间的直接绑定。如果愿意,您可以尝试重写此行为,但如果您满足于在实现中直接使用ActiveRecord,那么您是否也满足于在测试中这样做

d1_status = ActiveRecord::Base.connection.execute("SELECT status from history where id = #{device1.id} limit 1;").values[0][0]
expect(d1_status).to eq("Offline")

不过,我注意到一些令人不安的推论。您正在编辑历史记录表,但预期的结果可能是设备型号。状态方法的实现也与您的问题相关。如果选择此方法,您可能希望为Devicestatus方法编写其他测试。

您肯定不希望不清理数据库。至少你想要截断。不清洗意味着测试污染。还要注意的是,您的查询存在SQL注入漏洞。我想不出您无法正常测试该漏洞的原因,我认为数据库清理器是一个骗局。如果您使用普通的活动记录而不是执行,您的测试是否通过?我很好奇,您正在重新加载现有对象以测试其状态,而您发布的代码段似乎将新行插入到不同的表中。在沙盒控制台上运行查询时,输出是什么?在我看来,您的查询缺少最后一个“;”。通常,此工作流是可测试的。我建议直接在数据库中验证SQL。也许你需要使用严肃的字符而不是appostrophs'device\u id'而不是'device\u id'。。。这取决于您的SQL引擎。
d1_status = ActiveRecord::Base.connection.execute("SELECT status from history where id = #{device1.id} limit 1;").values[0][0]
expect(d1_status).to eq("Offline")