测试 rspec 中 关于 Test Doubles 的问题

tsinghan · 2012年11月13日 · 最后由 tumayun 回复于 2012年11月14日 · 6028 次阅读

RSpec Mocks 中是这样描述的,但是没看懂是什么意思,和具体用法。。。

Test Doubles A Test Double is an object that stands in for a real object in a test. RSpec creates test doubles that support method stubs and message expectations.

book = double("book")

这个问的太笼统了,具体点再问,或者上代码

@TsingHan

#1 楼 @knwang 额,之前写测试没有用过 double 比如说 book = double("book") 这句代码 有什么作用呢?或者你能否举个简单的例子 说明一下 其用法?

#2 楼 @TsingHan 你以前写测试用的是什么?

#3 楼 @knwang 比如说 这样的写法 customer.stub(:name).and_return('Bryan')

Both mock and stub are aliases of the more generic double. Like context and describe, they can be used interchangeably to make the intent of the specs more clear. This is described in a lot more detail in The RSpec Book.

http://stackoverflow.com/questions/7359722/in-rspec-whats-the-difference-between-a-mock-and-a-double

rspec-mocks helps to control the context in a code example by letting you set known return values, fake implementations of methods, and even expectations that specific messages are received by an object.

You can also use the mock and stub methods to create test doubles, however these methods are there for backward compatibility only and will likely be deprecated and then removed from future versions.

https://www.relishapp.com/rspec/rspec-mocks/docs

所以 double 和 stub、mock 其实都是用来生成 mock 对象的。

stub, mock 和 double 在 rspec 里面是同义词,可以混着用

我一般很少用 double, 而是或者用 stub (mocking state) 或者用 mock (mocking interaction)

#4 楼 @TsingHan

double 这个单词的意思是替身,就是把真的对象换成假的,用来创造一些测试条件(状态)。

#6 楼 @knwang 奥 应该都是别名,就像 context 和 describe 类似 吧

#6 楼 @knwang 官方推荐使用 double,而不是 stub 和 mock

#5 楼 @zhangyuan 应该都是些 alias 但是 下面例子中的 double 有什么作用?没看懂 customer = double('customer') customer.stub(:name).and_return('Bryan')

#9 楼 @zhangyuan 在这个上我不同意官方的推荐

#11 楼 @knwang 平时也只是用 stub 和 mock 似乎容易理解些

#7 楼 @pongyo customer = double('customer') customer.stub(:name).and_return('Bryan') 上面的 double 什么意思呢 没看懂?

#13 楼 @TsingHan 第一个是生成一个对象,没有其他行为;第二个还假定了这个对象接受的 方法和返回值。

这样说可以吗?

上面的 double 就是创造一个替身对象呀。

或者可以这样理解。double 用来生成“假”对象,stub 方法用来生成这个对象上的“假”方法?

#16 楼 @zhangyuan #15 楼 @pongyo 奥 我应该理解了 我先试一下 再回复你们

#9 楼 @zhangyuan stub 和 mock 在测试领域内有不同的语意区别。在实现上确实可以互用,但是区别开可以让我扫一眼就知道测试对象的功用

比如说如果我的代码里面有

book = mock 我就知道我的当下测试对象在后面要传给 book 消息 / 这个对象会合我的测试对像交互

stub 在严格的隔离单元测试里面用的不多,但在功能测试里面会用到多些。比如如果我用了

book = stub(:book, title: "a book") 我就知道我的测试重点不在于对 book 的交互,而是需要一个有 'a book' 内部状态的对象

#17 楼 @knwang @zhangyuan @pongyo 我刚才跑了一下测试 user = User.new user.stub(:user_name).and_return("dsg") user = double(:user_name => "dsg") 这样 其实效果应该都是一样的 同样的能给 user 的 user_name 赋值,只是写法不同而已 对吧

源码如下

def double(*args)
  declare_double('Double', *args)
end

def mock(*args)
  declare_double('Mock', *args)
end

def stub(*args)
  declare_double('Stub', *args)
end

#18 楼 @knwang

#18 楼 @knwang

谢谢回复,这几个英文单词对我来说,都比较抽象,得多看看例子才能理解的。再看了一下文档,我之前的回复有问题。官网说的推荐用 double,是在 Test Doubles 这一节,而不是所有使用 stub 和 mock 的地方。应该是在你说的第一种情况,接下来可能要测试这个对象是否是否接收了某些消息。

而第二种情况使用 stub,常常和方法在一起(所以有个章节叫 Message Stub?),用来模拟有内部状态的对象。一般接下来不会测试这个对象。

• Dummy Object • Test Stub • Test Spy • Mock Object • Fake Object

#21 楼 @zhangyuan 嗯,测试的这些理念大都是先于 Ruby, Rspec 这些就有了的,stub, mock, double, spy, fake, doummy 这些的概念都不一样。Rspec 的这些人说,别麻烦了,都用 double 就好了。但还是有老学究们喜欢在细分些

#19 楼 @TsingHan

有细微的差别,第一种情况下你的测试代码对 User 的这个类有依赖性,所以隔离型单元测试的拥护者会指出你的那个不是单元测试,而是功能测试。比如说如果以后你想把 User 这个类改名叫 Person 你会发现这个和 User 没什么关系的测试也会爆了

#19 楼 @TsingHan

有细微的差别,第一种情况下你的测试代码对 User 的这个类有依赖性,所以隔离型单元测试的拥护者会指出你的那个不是单元测试,而是功能测试。比如说如果以后你想把 User 这个类改名叫 Person 你会发现这个和 User 没什么关系的测试也会爆了

怎么删除重复的回答?

#26 楼 @knwang 好像只能修改回复吧

#26 楼 @knwang 好像只能修改回复吧

#29 楼 @TsingHan 你的头像是谁,看着眼熟

#26 楼 @knwang 哈哈 迈克尔欧文啊

哈 我还以为是 Matt Damon

刚才看了下源码,对于rspec而言,stub double mock 实现上都是一样的, 最终用到的都是stub来实现 https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/test_double.rb#L96

只是在语义上有些区别,能很容易的理解你的测试

需要 登录 后方可回复, 如果你还没有账号请 注册新账号