希望MiniTest人员能够提出一个简单的问题..
我有一段代码,我将在这里压缩成一个例子:
import csv
Mysum = 0
input_attribute = input("Enter attribute for comparison (lowercase) :")
input_SetNum = input("How many data sets are you comparing: ")
print ("You entered " + input_SetNum)
data_sets = {}
for i in range(1, int(input_SetNum)+1):
with open(input("Please enter the file name with .csv: ")) as csvfile:
reader = csv.DictReader(csvfile)
for row in reader: # The code in your `for` block needs to be indented or you're going to get more errors...
data_sets[i] = (row[input_attribute])
print (data_sets[i])
Mysum = sum(data_sets[i])
print(Mysum)
我如何模拟/存根/其他东西,以便我可以提供class Foo
def initialize(name)
@sqs = Aws::SQS::Client.new
@id = @sqs.create_queue( queue_name: name ).fetch(:queue_url)
@poller = Aws::SQS::QueuePoller.new(@id)
end
def pick_first
@poller.poll(idle_timeout: 60) do |message|
process_msg(message) if some_condition(message)
end
end
以通过message
进行测试,并可能使用some_condition()
进行处理?
即。我想测试process_msg()
。
我曾尝试使用模拟轮询器来存储@poller.poll(idle_timeout: 60) do |message|
,但它不会将消息传递给Aws::SQS::QueuePoller#new
只是返回它..
这就是我所拥有的,不正在工作:
|message|
如果我在mockqueue = MiniTest::Mock.new
mocksqs = MiniTest::Mock.new
mocksqs.expect :create_queue, mockqueue, [Hash]
mockpoller = MiniTest::Mock.new
mockpoller.expect :poll, 'message', [{ idle_timeout: 60 }]
Aws::SQS::Client.stub :new, mocksqs do
Aws::SQS::QueuePoller.stub :new, mockpoller do
queue = Foo.new(opts)
queue.pick_first
end
end
收到变量,那就是模拟放置的变量,而不是#pick_first
:
|message|
答案 0 :(得分:5)
回答我自己的问题,以防其他人有同样的问题。
我通过Twitter寻求帮助,MiniTest的作者,Ryan Davis(又名@zenpider on github / @the_zenspider on Twitter)给出了快速回答以及邀请将问题提交给MiniTest github问题跟踪器
I did so,得到了一些很好的回应,来自Ryan和Pete Higgins(@phiggins on github),我在这里完整地再现。谢谢你们两位的帮助!
如下:
class Foo def initialize(name, opts={}) @sqs = Aws::SQS::Client.new @id = @sqs.create_queue( queue_name: name ).fetch(:queue_url) @poller = opts.fetch(:poller) { Aws::SQS::QueuePoller.new(@id) } end def pick_first @poller.poll(idle_timeout: 60) do |message| process_msg(message) if some_condition(message) end end end # later, in your tests describe Foo do it "does the thing in the block" do # could be moved into top-level TestPoller, or into shared setup, etc. poller = Object.new def poller.poll(*) ; yield ; end foo = Foo.new("lol", :poller => poller) foo.pick_first assert foo.some_state_was_updated end end
注意:我是反模拟的。对于这个问题我几乎是反对的。恕我直言,如果 你不能在没有嘲笑的情况下测试一些东西,你可能有一个 设计问题。根据以下文字进行相应校准。
我建议使用Liskov Substitution Principal(LSP),因为我是 专注于测试process_msg做了正确的事情 上下文。这个想法很简单,子类,覆盖了方法 问题,并在测试中使用子类。 LSP说测试 子类相当于测试超类。
对于投票对象,您有三个问题(民意调查, 过滤和处理)在那个方法中进行,其中一个你 不应该测试(因为它是第三方代码)。我会重构 像这样的东西:
class Foo # .... def poll @poller.poll(idle_timeout: 60) do |message| yield message end end def pick_first poll do |message| process_msg(message) if some_condition(message) end end end
然后测试是一件简单的事情:
class TestFoo1 < Foo def poll yield 42 # or whatever end # ... end # ... assert_equal 42, TestFoo1.new.pick_first # some_condition truthy assert_nil TestFoo2.new.pick_first # some_condition falsey
有更短/“rubyier”的方法可以做到这一点,但它们与上面相同,上面说明了这一点。
答案 1 :(得分:0)
我试图对产生障碍的东西进行存根处理,但找不到答案。 (不确定这是否正是您的要求。)这是操作方法。
这是我们要模拟的课程:
class Foo
def bar
yield(42)
end
end
在测试中,我们实例化了对象:
foo = Foo.new
然后,我们可以使用普通的Ruby覆盖此方法以执行其他操作:
def foo.bar
yield(16)
end
现在,当我们调用它时,它会调用存根版本:
foo.bar do |value|
puts value
# => 16
end
足够容易。这花了我一段时间才能弄清楚。希望这对某人有帮助:)