使 用 Mock object
 进 行 测 试
    张   元   一
什么是Mock object?
wikipedia

Mock object 是面向对象编程中
,对真实对象的行为以可控的
方式进行模拟的一种虚拟对象
汽车碰撞测试中的模型人
为什么需要Mock object?
1.降低代码耦合
一个改动导致大量测试失败
def test_create
  post :create, :user =>
     {:name => 'test'}
end

def test_update
  put :update, :user =>
     {:name =...
add_column :first_name
add_column :last_name
remove_column :name



      挂了!
2. 人生短暂,珍惜时间
不要重复测试


A测试例中已经测试过的代
码没必要再在B测试例中进
行测试,尤其是这些代码很耗
时
# post_test.rb
def test_should_create_post
  post = Post.new(...)
  assert post.valid?
end

class post
  validates_presenc...
# posts_controller_test.rb
def test_should_create_post
  post :create,
          :post => {...}
  ...
end
# posts_controller.rb
def create
  post = Post.new(params[:post])
  if post.save
    ...
end



          重复了!
3.让自己更轻松
等待是人世间最痛苦的事情之一,
尤其是你苦苦等待的结果居然是:


   Failure!
如何使用Mock object?
Mocha, Flex Mock or RSpec
Mocha
@post = mock(“post”)

@post = Post.new
@post = mock(“post”)
@post.digg


#<Mock:post>.digg -
expected calls: 0, actual
calls: 1
@post.expects(:digg)


@post.instance_eval {
  def digg
    ...
  end
}
def test_xxx
  @post.expects(:digg)
end


#<Mock:post>.digg -
expected calls: 1, actual
calls: 0
@post.expects(:digg).once
at_least(min)
at_least_once
at_most(max)
at_most_once
never
times(num)
if @post.digg # nil
  ...
else
  ...
end
@post.expects(:digg)
    .returns(true)

@post.expects(:digg)
    .raises(exception)
@post.digg(@blocked) # false
@post.digg(@unblocked) # true

@post.expects(:digg)
   .with(any_of(User.blocked))
   .return...
all_of
any_of
anything
has_entry(key, value)
has_key(key)
has_value(value)
includes(item)
instance_of(klass)
kind_of(klass...
@post.expects(:method)
    .at_least(0)
@post.expects(:method)
    .at_least(0)
    .returns(:result)

@post.stubs(:method...
@post = stub_everything('post'
    :method => :result)



@post.method1 # nil
@post.method2 # nil
@post.method # :result
Mocha on Rails
def test_create
  post :create, :user =>
     {:name => 'test'}
end

add_column :first_name
add_column :last_name
remove_c...
def test_should_create_user
  Post.expects(:new)
          .returns(@post)
  @post.expects(:save)
          .returns(true)...
告别Fixture!
# teachers_students.yml
       one:
         teacher_id: 1
不够直观     student_id: 1
       two:
         teacher_id: 1
浪费时间 ...
def setup
  @user = User.new(:name=>'test')
  @post1 =
Post.new(:title=>'post1')
end
def test_should_show_post
  User.expe...
RSpec
it “should create a new user” do
  User.should_receive(:new)
          .and_return(@user)
  User.stub!(:save)
          .a...
Flex Mock?



同样的思想,不同的实现!
问题?
谢谢!
Upcoming SlideShare
Loading in …5
×

Testing with mock object

4,461 views

Published on

shanghaionrails first event presentation by zhanyuanyi

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,461
On SlideShare
0
From Embeds
0
Number of Embeds
32
Actions
Shares
0
Downloads
88
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Testing with mock object

  1. 1. 使 用 Mock object 进 行 测 试 张 元 一
  2. 2. 什么是Mock object?
  3. 3. wikipedia Mock object 是面向对象编程中 ,对真实对象的行为以可控的 方式进行模拟的一种虚拟对象
  4. 4. 汽车碰撞测试中的模型人
  5. 5. 为什么需要Mock object?
  6. 6. 1.降低代码耦合
  7. 7. 一个改动导致大量测试失败
  8. 8. def test_create post :create, :user => {:name => 'test'} end def test_update put :update, :user => {:name => 'new'} end
  9. 9. add_column :first_name add_column :last_name remove_column :name 挂了!
  10. 10. 2. 人生短暂,珍惜时间
  11. 11. 不要重复测试 A测试例中已经测试过的代 码没必要再在B测试例中进 行测试,尤其是这些代码很耗 时
  12. 12. # post_test.rb def test_should_create_post post = Post.new(...) assert post.valid? end class post validates_presence_of :xxx end
  13. 13. # posts_controller_test.rb def test_should_create_post post :create, :post => {...} ... end
  14. 14. # posts_controller.rb def create post = Post.new(params[:post]) if post.save ... end 重复了!
  15. 15. 3.让自己更轻松
  16. 16. 等待是人世间最痛苦的事情之一, 尤其是你苦苦等待的结果居然是: Failure!
  17. 17. 如何使用Mock object?
  18. 18. Mocha, Flex Mock or RSpec
  19. 19. Mocha
  20. 20. @post = mock(“post”) @post = Post.new
  21. 21. @post = mock(“post”) @post.digg #<Mock:post>.digg - expected calls: 0, actual calls: 1
  22. 22. @post.expects(:digg) @post.instance_eval { def digg ... end }
  23. 23. def test_xxx @post.expects(:digg) end #<Mock:post>.digg - expected calls: 1, actual calls: 0
  24. 24. @post.expects(:digg).once at_least(min) at_least_once at_most(max) at_most_once never times(num)
  25. 25. if @post.digg # nil ... else ... end
  26. 26. @post.expects(:digg) .returns(true) @post.expects(:digg) .raises(exception)
  27. 27. @post.digg(@blocked) # false @post.digg(@unblocked) # true @post.expects(:digg) .with(any_of(User.blocked)) .returns(false) @post.expects(:digg) .with(any_of(User.unblocked)) .returns(true)
  28. 28. all_of any_of anything has_entry(key, value) has_key(key) has_value(value) includes(item) instance_of(klass) kind_of(klass) regexp_matches(regexp)
  29. 29. @post.expects(:method) .at_least(0) @post.expects(:method) .at_least(0) .returns(:result) @post.stubs(:method) @post.stubs(:method => :result)
  30. 30. @post = stub_everything('post' :method => :result) @post.method1 # nil @post.method2 # nil @post.method # :result
  31. 31. Mocha on Rails
  32. 32. def test_create post :create, :user => {:name => 'test'} end add_column :first_name add_column :last_name remove_column :name
  33. 33. def test_should_create_user Post.expects(:new) .returns(@post) @post.expects(:save) .returns(true) post :create, :user => {} assert_redirect_to user_path(@user) end
  34. 34. 告别Fixture!
  35. 35. # teachers_students.yml one: teacher_id: 1 不够直观 student_id: 1 two: teacher_id: 1 浪费时间 student_id: 2 three: teacher_id: 2 student_id: 3
  36. 36. def setup @user = User.new(:name=>'test') @post1 = Post.new(:title=>'post1') end def test_should_show_post User.expects(:find) .returns(@user) @user.posts.expects(:find) .returns(@post1) get :show, :id=>1, :user_id=>1 assert_response :success end
  37. 37. RSpec
  38. 38. it “should create a new user” do User.should_receive(:new) .and_return(@user) User.stub!(:save) .and_return(true) post :create, :user => {} response.should redirect_to(user_path(@user)) end
  39. 39. Flex Mock? 同样的思想,不同的实现!
  40. 40. 问题?
  41. 41. 谢谢!

×