我正在尝试创建一个与Rails assert_difference
类似的最小的断言,但它会检查任何差异而不仅仅是数字差异。
这是我目前的实施:
Minitest::Assertions.module_eval do
def assert_changed(expression, &block)
unless expression.respond_to?(:call)
expression = lambda{ eval(expression, block.binding) }
end
old = expression.call
block.call
refute_equal old, expression.call
end
end
现在在我的测试套件中,我通过执行以下操作来调用它:
# this is working
username = 'Jim'
assert_changed lambda{ username } do
username = 'Bob'
end
# this is not working
username = 'Jim'
assert_changed 'username' do
username = 'Bob'
end
使用lambda(或proc)对assert_changed
的第一次调用完全正常。使用带有变量名称的字符串的第二次调用无效。
当它到达此行时:expression = lambda{ eval(expression, block.binding) }
我一直收到错误TypeError: no implicit conversion of Proc into String
。有人可以向我解释如何让它发挥作用吗?
注意:我从Rails assert_difference
方法获得了eval(expression, block.binding)
想法。
答案 0 :(得分:1)
当它到达此行时:
as_strided
我一直收到错误expression = lambda{ eval(expression, block.binding) }
。
我有理由相信你在点击那条线时不得到那个错误,而是在击中这条线时:
TypeError: no implicit conversion of Proc into String
因此,异常不是由分配触发的,而是在old = expression.call
Proc
被call
编辑并且eval
被执行后触发的。
此时,它会调用Proc
中存储的expression
。存储在Proc
中的expression
如下所示:
eval(expression, block.binding)
Kernel#eval
的第一个参数必须是可隐式转换为String
的内容(即响应to_str
的内容),但它是Proc
。你会得到TypeError
。
最简单的方法是重命名变量:
new_expression = expression
unless expression.respond_to?(:call)
new_expression = lambda{ eval(expression, block.binding) }
end
old = new_expression.call
block.call
refute_equal old, new_expression.call
就个人而言,我可能更喜欢这样写:
module Minitest::Assertions
def assert_changed(expression, &block)
new_expression = if expression.respond_to?(:call)
expression
else
-> { block.binding.eval(expression) }
end
old = new_expression.()
block.()
refute_equal old, new_expression.()
end
end
没有(无用的)Module#module_eval
,并使用call
运算符语法和->
stabby lambda文字语法。