Ruby 如何测试线程中是否调用了块?
我正在将Ruby 如何测试线程中是否调用了块?,ruby,multithreading,rspec,publish-subscribe,mqtt,Ruby,Multithreading,Rspec,Publish Subscribe,Mqtt,我正在将ruby mqttgem包装到一个类中,该类实现了subscribe和publish方法。subscribe方法连接到服务器并在单独的线程中侦听,因为此调用是同步的 module PubSub class MQTT attr_accessor :host, :port, :username, :password def initialize(params = {}) params.each do |attr, value| sel
ruby mqtt
gem包装到一个类中,该类实现了subscribe
和publish
方法。subscribe
方法连接到服务器并在单独的线程中侦听,因为此调用是同步的
module PubSub
class MQTT
attr_accessor :host, :port, :username, :password
def initialize(params = {})
params.each do |attr, value|
self.public_send("#{attr}=", value)
end if params
super()
end
def connection_options
{
remote_host: self.host,
remote_port: self.port,
username: self.username,
password: self.password,
}
end
def subscribe(name, &block)
channel = name
connect_opts = connection_options
code_block = block
::Thread.new do
::MQTT::Client.connect(connect_opts) do |c|
c.get(channel) do |topic, message|
puts "channel: #{topic} data: #{message.inspect}"
code_block.call topic, message
end
end
end
end
def publish(channel = nil, data)
::MQTT::Client.connect(connection_options) do |c|
c.publish(channel, data)
end
end
end
end
我使用rspec编写了一个测试来测试这个类,但它没有通过
mqtt = ::PubSub::MQTT.new({host: "localhost",port: 1883})
block = lambda { |channel, data| puts "channel: #{channel} data: #{data.inspect}"}
block.should_receive(:call).with("channel", {"some" => "data"})
thr = mqtt.subscribe("channel", &block)
mqtt.publish("channel", {"some" => "data"})
当我运行以下程序时,我现在遇到了所有问题
uri = URI.parse ENV['CLOUDMQTT_URL'] || 'mqtt://localhost:1883'
conn_opts = {
remote_host: uri.host,
remote_port: uri.port,
username: uri.user,
password: uri.password,
}
# Subscribe example
Thread.new do
puts conn_opts
MQTT::Client.connect(conn_opts) do |c|
# The block will be called when you messages arrive to the topic
c.get('test') do |topic, message|
puts "#{topic}: #{message}"
end
end
end
# Publish example
puts conn_opts
MQTT::Client.connect(conn_opts) do |c|
# publish a message to the topic 'test'
loop do
c.publish('test', 'Hello World')
sleep 1
end
end
所以我的问题是,当我简单地创建一个类并分离出发布和订阅逻辑时,我做错了什么?我猜这与函数调用中的线程有关,但我似乎无法理解。非常感谢您的帮助
更新
我相信我知道为什么测试没有通过,这是因为当我将
lambda
in传递到subscribe
期望它接收调用时,它实际上不会在退出方法或调用publish
之前接收调用。所以我想把这个问题重新表述为:如何测试在线程中调用了块?如果有人回答“您没有”,那么问题是:如何测试在无限循环中调用该块,就像在ruby mqtt
gem中调用get
的示例中一样。RSpec期望机制将与线程一起正常工作,如下例所示,它通过了:
def foo(&block)
block.call(42)
end
describe "" do
it "" do
l = lambda {}
expect(l).to receive(:call).with(42)
Thread.new { foo(&l) }.join
end
end
join
等待线程完成,然后再继续。您会遇到什么错误?您是否在rspec测试片段的末尾执行sleep
?可能是测试用例在另一个线程有机会调用块上的call
之前退出。我尝试了两秒钟的睡眠,但我将尝试更长的睡眠时间。我没有得到任何错误。考试就是不及格。谢谢你的帮助@north636。获取通道:通道数据:{“some”=>“data”}中较长的睡眠时间
,记录到控制台,显示正在调用get
中的块,但我的测试未通过。我修改了我的问题,问我如何测试这个代码。你把你的睡眠放在哪里了?正如@north636所说的和我在回答中所显示的,它需要在RSpec块的末尾。我在和你的例子相同的地方睡觉。你的例子和我的测试之间的区别是,我也在检查它在调用中是否有一个参数,即block.should\u receive(:call)。使用({“some”=>“data”})
我将排除你的答案,因为它确实让我的测试通过了,这就足够了。但是我想知道为什么断言块应该接收某些参数会导致测试失败。我已经更新了示例,将与
一起使用。如果你能分享你得到的具体错误,这会有帮助。