[Unit Testing for Zombie] 04. Mock and Stub

STUBBING

Notice how the show_author_summary method in tweet is calling the zombie_summarymethod inside zombie. This isn't good! Stub out the zombie_summary method in the test below.

tweet.rb

复制代码
class Tweet < ActiveRecord::Base
  belongs_to :zombie
 
  validates :status, presence: true, length: {within: 3..140, allow_blank: true}
  validates :zombie, presence: true
  
  def brains?
    status =~ /(brains|breins)/i
  end
 
  def show_author_summary
    self.status = self.zombie.zombie_summary
  end
 
  def status_image
    image = ZwitPic.get_status_image(self.id) # This is returning an array
    {image_name: image[0], image_url: image[1]}
  end
end
复制代码

zombie.rb

复制代码
class Zombie < ActiveRecord::Base
  has_many :tweets
 
  validates :name, presence: true, length: {maximum: 15}, uniqueness: {case_sensitive: false}
  validates :graveyard, presence: true
 
  def to_param
    name
  end
  
  def zombie_summary
    "#{name} lives in #{graveyard} and has #{self.tweets.size} tweets"
  end
  
  def geolocate
    loc = Zoogle.graveyard_locator(self.graveyard)
    "#{loc[:latitude]}, #{loc[:longitude]}"
  end
  
  def geolocate_with_object
    loc = Zoogle.graveyard_locator(self.graveyard)
    "#{loc.latitude}, #{loc.longitude}"
  end
  
  def avatar_url
    "http://zombitar.com/#{id}.jpg"
  end
end
复制代码
复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "show_author_summary should set status to zombie summary" do 
    @tweet.show_author_summary
    assert_equal @tweet.zombie.zombie_summary, @tweet.status, 'tweet status does not contain zombie summary'
  end
end
复制代码

 

Answer:

First use stubs to call zombie_summary method, it is a fake calling, but set the value of status.

It should before the @tweet.show_author_summary line.

复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "show_author_summary should set status to zombie summary" do 
    @tweet.zombie.stubs(:zombie_summary)
    @tweet.show_author_summary
    assert_equal @tweet.zombie.zombie_summary , @tweet.status, 'tweet status does not contain zombie summary'
  end
end
复制代码

 

MOCKING

Create another test to make sure zombie_summary is actually called in theshow_author_summary method using a mock.

复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "show_author_summary should call zombie_summary" do
    @tweet.zombie.expects(:zombie_summary)
    @tweet.show_author_summary
  end
end
复制代码

 

STUB + ASSERT

Notice how the status_image method in Tweet calls ZwitPic.get_status_image, potentially a remote server call. Create a test which mocks this method and ensures the correct params get sent.

复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "status_image calls the ZwitPic get_status_image api" do 
    ZwitPic.expects(:get_status_image).with(@tweet.id)
    @tweet.status_image
  end
end
复制代码

Dont forget to call status_image mthod after stubs the get_status_image, because get_status_image is stubbed, but it is inisde status_images method.

 

STUBS & MOCKING

Notice how the status_image method now has a return value which is expecting image to be an Array. Modify the mock to return an array with two string values.

复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "status_image calls the ZwitPic get_status_image api" do 
    ZwitPic.expects(:get_status_image).with(@tweet.id).returns(['Scary Zombie', 'http://zwitpic.com/scary_zombie.png'])
    @tweet.status_image
  end
end
复制代码

 

RETURNING PROPER RESULTS

Notice that the status_image method on Tweet now returns an HTML image tag with an alt attribute set to the image name, and the ZwitPic.get_status_image method is now returning a hash. Write a test which stubs, instead of mocks, get_status_image and tests that @tweet.status_image returns the proper result (which should also be an image tag).

  def status_image
    status_image = ZwitPic.get_status_image(self.id)
    "<img src='#{status_image[:url]}' alt='#{status_image[:name]}' />".html_safe
  end

Answer:

复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "status_image returns a properly formated HTML image element with alt and src" do
    #using stubs to test get_status_image is called and set the value
    #with(): send the param
    #returns(): mock a return value
    ZwitPic.stubs(:get_status_image).with(@tweet.id).returns({name: "Gegg", url: "http://monxp.com/monkey.png"})
    assert_equal "<img src='http://monxp.com/monkey.png' alt='Gegg' />",  @tweet.status_image 
  end
end
复制代码

 

OBJECT STUB

Notice how the get_status_image is now returning an object. Using an object stub, refactor the previously created test.

  def status_image
    image = ZwitPic.get_status_image(self.id)
    "<img src='#{image.url}' alt='#{image.name}' />".html_safe
  end

Answer:

复制代码
class TweetTest < ActiveSupport::TestCase
  def setup
    @tweet = tweets(:hello_world)
  end

  test "status_image returns a properly formated HTML image element with alt and src" do
    image = stub(name: "Yummy brain I ate last night", url: "http://zwitpic.com/2.jpg")
    ZwitPic.stubs(:get_status_image).with(@tweet.id).returns(image)
    assert_equal "<img src='http://zwitpic.com/2.jpg' alt='Yummy brain I ate last night' />", @tweet.status_image
  end
end
复制代码

 

posted @   Zhentiw  阅读(370)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示