我正在使用这个名为kubernetes_leader_election
的gem编写一些代码,它在其README中有一个完整的示例来展示如何使用它。我对它的使用基本上与README中所说的相同,但这里是最相关的行:
lease_name = self.class.name.underscore.gsub(/[\/_]+/, "=")
is_leader = false
elector = KubernetesLeaderElection.new(lease_name, kubeclient, logger: Rails.logger)
Thread.new { elector.become_leader_for_life { is_leader = true } }
sleep 1 until is_leader
字符串
我试着写一个spec来测试我传入的lease_name
是我期望的,并且如果块{ is_leader = true }
执行,代码不会永远休眠。我知道如何mock KubernetesLeaderElection.new
,但我对使用rspec mock有点陌生,所以我真的很难模仿elector.become_leader_for_life
,(能够测试它传递的内容)。我已经尝试了一系列关于这个整体概念的变体,但没有一个能完全满足我的需要,而且大多数都有给予错误。这是我最新的尝试,它不会失败,但不会测试我想要的一切:
describe LeaderElectionMixin
class MixinUser
include LeaderElectionMixin
end
describe "#wait_to_be_leader" do
let(:dummy_client) { double(Kubeclient::Client) }
let(:dummy_elector) { double(KubernetesLeaderElection) }
before do
allow(Kubeclient::Client).to receive(:new).and_return(dummy_client)
expect(dummy_elector).to receive(:become_leader_for_life) do |&block|
# only checks that the actual block and this proc return the same thing
expect(block).to match(Proc.new { true })
end.and_yield
end
it "should create leases based on the class name" do
expect(KubernetesLeaderElection).to receive(:new)
.with("mixin-user", dummy_client, logger: Rails.logger)
.and_return(dummy_elector)
MixinUser.new.wait_to_be_leader
end
end
end
型
(EDIT更新:如果我使用.and_yield
,我可以解决rspec挂起的问题,但它还不是一个完整的解决方案,因为我不能测试块内容的实际匹配,因为.and_yield
使我的块不是链的末端,更多信息在这里。如果我将.and_yield
移到块之前,那么expect(block)
就是expect(nil)
。不知道为什么。)
我的方法遇到的问题是,rspec挂起,因为is_leader = true
没有执行,所以sleep 1 until is_leader
将永远运行,或者(在我的最新实现中)我可以让原始块执行,但我不能Assert它确实执行了,我只能推断它确实如此,因为规范结束了。expect(block).to be
或者是块代码的确切内容的字符串,或者是包含相同代码的Proc,但方法不起作用,因为实际值是Proc(所以使用字符串的建议不起作用),而且它不是同一个Proc对象(所以be
和eq
不工作。)我也试过将.and_wrap_original
附加到不同的地方,但这要么给我一个错误,要么给我和这个例子一样的行为。我能做的最好的是match
,至少检查块的返回值和我做的Proc是一样的。我完全迷路了,我知道我可以切换到使用示例变量,但我不想将它暴露给包括我的mixin在内的类。
总结一下,我:
1.绝对需要最内部的块is_leader = true
来实际执行,并且想测试它的内容是否是我指定的;
1.绝对需要中间的块elector.become_leader_for_life
,不调用原始代码(因为它是第三方库,我不想模仿它的实现细节;)
1.不要真的关心外层Thread.new
是否真的执行(规范不需要代码是多线程的,这只是为了运行时效率,因此我为我的规范模拟了sleep
。)
我如何才能实现这种“只模拟中间块”的行为,而不诉诸于用模拟气味(如使用示例变量)污染代码?
1条答案
按热度按时间i1icjdpr1#
我不知道这是干什么的:
字符串
但是代码:
型
不会执行它接收到的块,所以
is_leader
永远不会改变。假设你可以得到一个块的源代码,你可以做一些像这样的事情:
型
可能与
block.call
有条件的块源?