如何测试未执行的 if 条件?

How to test an if-condition not been excuted?

我是 Rspec 的新手。我有这样的代码:

if @context.persona == :system && @context.scopes&.include?(SEARCH_SCOPE)
  return <something>
end

我想写一个单元测试来确认当@context.persona 不是 :system 时 @context.scopes&.include?(SEARCH_SCOPE) 没有被执行。这是我写的:

context 'when persona is system' do
  let(:persona) { :system }
  
  it 'checks the scope' do
     allow(context).to receive(:scopes)

     expect(context).to have_received(:scopes)
  end
end

context 'when persona is not system' do
  let(:persona) { :user }
  
  it 'checks the scope' do
     allow(context).to receive(:scopes)

     expect(context).not_to have_received(:scopes)
  end
end

第二个测试通过,但第一个测试失败:

     Failure/Error: expect(context).to have_received(:scopes)
     
       (Double (anonymous)).scopes(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

有人可以帮助我吗?我之前用谷歌搜索过,但没有看到任何有用的信息。如有重复请见谅

不是您问题的直接答案,但您正在掉入测试实施的坑,而不是行为。不要那样做。

你的测试不应该关心这个:

expect(context).not_to have_received(:scopes)

相反,您的测试应该只做这样的事情:

context 'when persona is system and scopes includes SEARCH_SCOPE' do
  let(:persona) { :system }
  let(:scopes) { ... }
  
  it 'returns <something>' do
     expect(the_method_being_invoked).to eq(<something>)
  end
end

context 'when persona is not system' do
  let(:persona) { :user }
  let(:scopes) { ... }
  
  it 'returns <something-else>' do
     expect(the_method_being_invoked).to eq(<something-else>)
  end
end

context 'when scopes is empty' do
  let(:persona) { :user }
  let(:scopes) { nil }
  
  it 'returns <something-else>' do
     expect(the_method_being_invoked).to eq(<something-else>)
  end
end

为什么?因为当您重构代码并且实现发生变化时,您不希望规范开始失败,除非 行为 也发生了变化。

您通常甚至应该能够在编写方法之前编写测试——因此不了解其实现细节。