RSpec是否有可能期望两个表的变化?

B S*_*ven 40 ruby rspec

RSpec期望改变:

it "should increment the count" do
  expect{Foo.bar}.to change{Counter.count}.by 1
end
Run Code Online (Sandbox Code Playgroud)

有没有办法预期两个表的变化?

expect{Foo.bar}.to change{Counter.count}.by 1 
and change{AnotherCounter.count}.by 1 
Run Code Online (Sandbox Code Playgroud)

Geo*_*ann 76

我更喜欢这种语法(rspec 3或更高版本):

it "should increment the counters" do
  expect { Foo.bar }.to change { Counter,        :count }.by(1).and \
                        change { AnotherCounter, :count }.by(1)
end
Run Code Online (Sandbox Code Playgroud)

是的,这是一个地方的两个断言,但因为块只执行了一次,它可以加速测试.

编辑:在.and避免语法错误后添加反斜杠

  • @ abhishek77in和@caesarsol:`和`需要在另一条线上,或者你需要将整个事情放在一条线上. (4认同)
  • 实际上,使用rspec 3组合会导致块被多次运行:(.叹气.感谢Cargo Cultists坚持谴责每个人进行集成测试,这些测试需要比他们需要的更长的运行时间. (3认同)
  • @MichaelJohnston我刚检查了复合匹配器,它只运行一次块.您是否可以在多次运行块时提供示例? (3认同)

Fre*_*ore 22

尝试使用@ MichaelJohnston的解决方案时出现语法错误; 这是最终为我工作的形式:

it "should increment the counters" do
  expect { Foo.bar }.to change { Counter.count }.by(1)
    .and change { AnotherCounter.count }.by(1)
end
Run Code Online (Sandbox Code Playgroud)

我应该提到我正在使用ruby 2.2.2p95 - 我不知道这个版本在解析中是否有一些微妙的变化导致我得到错误,看起来这个线程中没有其他人有这个问题.


Chr*_*ald 20

这应该是两个测试.RSpec最佳实践要求每次测试一个断言.

describe "#bar" do
  subject { lambda { Foo.bar } }

  it { should change { Counter.count }.by 1 }
  it { should change { AnotherCounter.count }.by 1 }
end
Run Code Online (Sandbox Code Playgroud)

  • 有时,这会产生大量的样板代码(当规范需要复杂的设置时).或者也许我只是做错了:) (7认同)
  • "这应该是两次测试." 当然,除非它不应该.就像它是一个集成测试,特别是外部服务的消费者.或者,如果它是对原子性或幂等性的测试,并且单独的副作用已经具有"适当的"单一断言覆盖,并且正在测试的是原子性/幂等性. (6认同)
  • @Arcolye你必须咬紧牙关并进行长达数小时的集成测试,如果有人抱怨它告诉他们你不能改变它,因为它会让BDD的上帝生气然后飞机不会来. (5认同)
  • 这对于模型/单元测试来说都很好,但是在功能/集成测试中,在一次测试中做出许多断言是正常的吗? (3认同)
  • 一般来说,如果我做了很多样板,我会尝试优化我的上下文/描述块,这样我就可以在块之前进行设置.这通常可以清理它. (2认同)

Uri*_*Uri 11

如果您不想使用之前建议的基于速记/上下文的方法,您也可以执行类似的操作,但要注意它会运行两次预期,因此可能不适合所有测试.

it "should increment the count" do
  expectation = expect { Foo.bar }
  expectation.to change { Counter.count }.by 1
  expectation.to change { AnotherCounter.count }.by 1
end
Run Code Online (Sandbox Code Playgroud)

  • 嗯,它仍然运行块两次. (7认同)

som*_*cto 5

Georg Ladermann 的语法更好,但不起作用。测试多个值更改的方法是组合数组中的值。否则,只有最后的更改断言才会决定测试。

我是这样做的:

it "should increment the counters" do
  expect { Foo.bar }.to change { [Counter.count, AnotherCounter.count] }.by([1,1])
end
Run Code Online (Sandbox Code Playgroud)

这与“.to”函数完美配合。

  • @somecto你的解决方案很接近,但请记住数组减法的定义:[1,1] - [] == [1,1],所以只要初始计数都是0,这个就会通过,但是如果初始计数例如,值是[1,3],那么你的测试减去[1,1] - [1,3],结果是[],所以它会失败。然而,有一个数据结构定义了您使用减法的方式:“Vector”。试试这个:`require 'matrix'`(在文件顶部)。`期望 { Foo.bar }. 更改 { Vector[Counter.count, AnotherCounter.count] }.by(Vector[1,1])` (4认同)
  • 不幸的是,这并没有按照您的想法进行。它只是断言最终计数为 [1, 1]。要明白我的意思,请使用一些已经存在的计数器记录来运行测试。 (3认同)