testing with mock object

Post on 19-Jan-2015

3.936 Views

Category:

Technology

9 Downloads

Preview:

Click to see full reader

DESCRIPTION

shanghaionrails first event presentation by zhanyuanyi

TRANSCRIPT

使 用 Mock object进 行 测 试

张 元 一

什么是Mock object?

Mock object 是面向对象编程中,对真实对象的行为以可控的方式进行模拟的一种虚拟对象

wikipedia

汽车碰撞测试中的模型人

为什么需要Mock object?

1.降低代码耦合

一个改动导致大量测试失败

def test_createpost :create, :user =>

{:name => 'test'}end

def test_updateput :update, :user =>

{:name => 'new'}end

add_column :first_nameadd_column :last_nameremove_column :name

挂了!

2. 人生短暂,珍惜时间

不要重复测试

A测试例中已经测试过的代码没必要再在B测试例中进行测试,尤其是这些代码很耗时

# post_test.rbdef test_should_create_postpost = Post.new(...) assert post.valid?

end

class postvalidates_presence_of :xxx

end

# posts_controller_test.rbdef test_should_create_postpost :create,

:post => {...}...

end

重复了!

# posts_controller.rbdef 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_onceat_most(max) at_most_oncenevertimes(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)) .returns(false)

@post.expects(:digg) .with(any_of(User.unblocked))

.returns(true)

all_ofany_ofanythinghas_entry(key, value) has_key(key) has_value(value) includes(item) instance_of(klass) kind_of(klass) regexp_matches(regexp)

@post.stubs(:method) @post.stubs(:method =>

:result)

@post.expects(:method) .at_least(0)

@post.expects(:method) .at_least(0) .returns(:result)

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

@post.method1 # nil@post.method2 # nil@post.method # :result

Mocha on Rails

def test_createpost :create, :user =>

{:name => 'test'}end

add_column :first_nameadd_column :last_nameremove_column :name

def test_should_create_userPost.expects(:new)

.returns(@post) @post.expects(:save)

.returns(true)

post :create, :user => {}assert_redirect_to

user_path(@user) end

告别Fixture!

# teachers_students.ymlone: teacher_id: 1student_id: 1

two:teacher_id: 1student_id: 2

three:teacher_id: 2student_id: 3

不够直观

浪费时间

def test_should_show_postUser.expects(:find)

.returns(@user) @user.posts.expects(:find)

.returns(@post1)

get :show, :id=>1, :user_id=>1assert_response :success

end

def setup@user = User.new(:name=>'test') @post1 =

Post.new(:title=>'post1') end

RSpec

it “should create a new user” doUser.should_receive(:new)

.and_return(@user) User.stub!(:save)

.and_return(true)

post :create, :user => {}response.should

redirect_to(user_path(@user)) end

同样的思想,不同的实现!

Flex Mock?

问题?

谢谢!

top related