Minitest::Mock
要点:
可使用delegator
每次expect只能被call一次
verify方法可加在每个test末尾,以验证是否所有expect都被正确地call过
摘自5.10:
def method_missing sym, *args, &block # :nodoc:
# 若未定义expect,也未定义delegator,或delegator没该方法,则报错
unless @expected_calls.key?(sym) then
if @delegator && @delegator.respond_to?(sym)
return @delegator.public_send(sym, *args, &block)
else
raise NoMethodError, "unmocked method %p, expected one of %p" %
[sym, @expected_calls.keys.sort_by(&:to_s)]
end
end
# 若@actual_calls显示已call过,则报错
# (一次expect只能call一次)
index = @actual_calls[sym].length
expected_call = @expected_calls[sym][index]
unless expected_call then
raise MockExpectationError, "No more expects available for %p: %p" %
[sym, args]
end
expected_args, retval, val_block =
expected_call.values_at(:args, :retval, :block)
if val_block then
# keep "verify" happy
@actual_calls[sym] << expected_call
raise MockExpectationError, "mocked method %p failed block w/ %p" %
[sym, args] unless val_block.call(*args, &block)
return retval
end
# 如果与expect的参数,数量或类型或值不同,报错
# (expect会默认零参数)
if expected_args.size != args.size then
raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
[sym, expected_args.size, args.size]
end
zipped_args = expected_args.zip(args)
fully_matched = zipped_args.all? { |mod, a|
mod === a or mod == a
}
unless fully_matched then
raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
[sym, args]
end
@actual_calls[sym] << {
:retval => retval,
:args => zipped_args.map! { |mod, a| mod === a ? mod : a },
}
retval
end