在 ruby 中模拟第 3 方对象的最佳方法是什么?
我正在使用 twitter gem 编写一个测试应用程序,我想编写一个集成测试,但我不知道如何模拟 Twitter 命名空间中的对象。这是我想要测试的函数:
def build_twitter(omniauth)
Twitter.configure do |config|
config.consumer_key = TWITTER_KEY
config.consumer_secret = TWITTER_SECRET
config.oauth_token = omniauth['credentials']['token']
config.oauth_token_secret = omniauth['credentials']['secret']
end
client = Twitter::Client.new
user = client.current_user
self.name = user.name
end
这是我正在尝试编写的 rspec 测试:
feature 'testing oauth' do
before(:each) do
@twitter = double("Twitter")
@twitter.stub!(:configure).and_return true
@client = double("Twitter::Client")
@client.stub!(:current_user).and_return(@user)
@user = double("Twitter::User")
@user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
但是,我收到此错误:
1) testing oauth twitter
Failure/Error: login_with_oauth
Twitter::Error::Unauthorized:
GET https://api.twitter.com/1/account/verify_credentials.json: 401: Invalid / expired Token
# ./app/models/user.rb:40:in `build_twitter'
# ./app/models/user.rb:16:in `build_authentication'
# ./app/controllers/authentications_controller.rb:47:in `create'
# ./spec/support/integration_spec_helper.rb:3:in `login_with_oauth'
# ./spec/integration/twit_test.rb:16:in `block (2 levels) in <top (required)>'
上面的模拟正在使用 rspec,但我也愿意尝试摩卡。任何帮助将不胜感激。
好的,感谢大家的帮助,我终于解决了这个问题。这是最后的测试:
feature 'testing oauth' do
before(:each) do
@client = double("Twitter::Client")
@user = double("Twitter::User")
Twitter.stub!(:configure).and_return true
Twitter::Client.stub!(:new).and_return(@client)
@client.stub!(:current_user).and_return(@user)
@user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
诀窍是弄清楚我需要在真实对象上存根 :configure
和 :new
并存根 :current_user
和双对象实例上的 :name
。
I'm writing a test app using the twitter gem and I'd like to write an integration test but I can't figure out how to mock the objects in the Twitter namespace. Here's the function that I want to test:
def build_twitter(omniauth)
Twitter.configure do |config|
config.consumer_key = TWITTER_KEY
config.consumer_secret = TWITTER_SECRET
config.oauth_token = omniauth['credentials']['token']
config.oauth_token_secret = omniauth['credentials']['secret']
end
client = Twitter::Client.new
user = client.current_user
self.name = user.name
end
and here's the rspec test that I'm trying to write:
feature 'testing oauth' do
before(:each) do
@twitter = double("Twitter")
@twitter.stub!(:configure).and_return true
@client = double("Twitter::Client")
@client.stub!(:current_user).and_return(@user)
@user = double("Twitter::User")
@user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
But, I'm getting this error:
1) testing oauth twitter
Failure/Error: login_with_oauth
Twitter::Error::Unauthorized:
GET https://api.twitter.com/1/account/verify_credentials.json: 401: Invalid / expired Token
# ./app/models/user.rb:40:in `build_twitter'
# ./app/models/user.rb:16:in `build_authentication'
# ./app/controllers/authentications_controller.rb:47:in `create'
# ./spec/support/integration_spec_helper.rb:3:in `login_with_oauth'
# ./spec/integration/twit_test.rb:16:in `block (2 levels) in <top (required)>'
The mocks above are using rspec but I'm open to trying mocha too. Any help would be greatly appreciated.
OK, I managed to figure this out thanks to everyone's help. Here's the final test:
feature 'testing oauth' do
before(:each) do
@client = double("Twitter::Client")
@user = double("Twitter::User")
Twitter.stub!(:configure).and_return true
Twitter::Client.stub!(:new).and_return(@client)
@client.stub!(:current_user).and_return(@user)
@user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
The trick was figuring out that I needed to stub :configure
and :new
on the real objects and stub :current_user
and :name
on a dobuled object instance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为问题在于您使用模拟的方式,您创建了模拟@twitter,但您从未真正使用过它。我认为您可能会有这样的印象:对 Twitter 的任何调用都将使用您指定的存根方法,但事实并非如此,只有对 @twitter 的调用才会被存根。
我使用 double ruby,而不是 rspec 模拟,但我相信你想做这样的事情:
这确保了无论何时你在 Twitter、Twitter::Client 上存根的方法被调用,它们都会按照你想要的方式响应。
另外,这似乎很奇怪,这是作为视图的一部分进行测试的,实际上应该是控制器测试的一部分,除非我遗漏了一些东西。
I think the problem is just the way you are using the mock, you created the mock @twitter, but you never actually use it. I think you may be under the impression that any calls to Twitter will use the stubbed methods you specified, but that's not how it works, only calls made to @twitter are stubbed.
I use double ruby, not rspec mocks, but i believe you want to do something like this instead:
This ensures that anytime the methods you stubbed on Twitter, Twitter::Client are called, they respond how you want.
Also, it seems strange that this is tested as part of a view, should really be part of a controller test instead unless i'm missing something.
您可以尝试使用类似 http://jondot.github.com/moxy/ 的内容。模拟网络请求
You can try using something like http://jondot.github.com/moxy/ . Mock Web Requests