【问题标题】:Ruby: const_set outside block?红宝石: const_set 块外?
【发布时间】:2014-04-14 22:40:53
【问题描述】:
我想mock a class with Ruby。
如何编写处理样板代码的方法?
以下代码:
module Mailgun
end
module Acani
def self.mock_mailgun(mock)
temp = Mailgun
const_set(:Mailgun, mock)
p Mailgun
yield
ensure
const_set(:Mailgun, temp)
end
end
Acani.mock_mailgun('mock') { p Mailgun }
打印:
"mock"
Mailgun
这里发生了什么?为什么Mailgun 是块内的原始值?这是否与 Ruby 绑定有关?
Ruby 版本:2.1.1p76
【问题讨论】:
标签:
ruby
mocking
block
metaprogramming
constants
【解决方案1】:
尝试将Object. 放在每个const_set 之前。
问题中的代码已简化。以下是相关代码:
test/test_helper.rb
require 'minitest/autorun'
module Acani
def self.const_mock(const, mock)
temp = const_get(const)
const_set_silent(const, mock)
yield
ensure
const_set_silent(const, temp)
end
private
def self.const_set_silent(const, value)
temp = $VERBOSE
$VERBOSE = nil
Object.const_set(const, value)
ensure
$VERBOSE = temp
end
end
test/web_test.rb
require 'test_helper'
require 'rack/test'
require_relative '../web'
class AppTest < MiniTest::Test
include Rack::Test::Methods
def app
Sinatra::Application
end
def test_password_reset
post '/users', {email: 'user1@gmail.com', password: 'password1'}
mailgun_mock = MiniTest::Mock.new
mailgun_mock.expect(:send, 200, [Hash])
Acani.const_mock(:Mailgun, mailgun_mock) do
post '/password_resets', {email: 'user1@gmail.com'}
end
mailgun_mock.verify
assert_equal 201, last_response.status
end
end