如何模拟“未实现”特定方法的内容?

时间:2015-03-06 22:26:44

标签: ruby unit-testing amazon-web-services rspec cucumber

背景:

我正在尝试使用黄瓜围绕AWS的接口进行一些测试驱动(或行为驱动)开发,在ruby中。

所以,我有一个步骤定义,如下所示:

Then(/^the mock object should have had :(.*?) called, setting "(.*?)" to "(.*?)"$/) do |method, param, value|
  expect(@mock).to receive(method.to_sym).with(hash_including(param, value))
end

以前使用以下设置@mock的位置:

@mock = instance_double(AWS::AutoScaling::Client)

我用以下功能行调用此步骤定义:

And the mock object should have had :update_auto_scaling_group called, setting "auto_scaling_group_name" to "Some-test-value"

当该步骤运行时,它会收到以下错误(遗漏完整错误,因为我认为这是最相关的部分):

  AWS::AutoScaling::Client does not implement: update_auto_scaling_group (RSpec::Mocks::MockExpectationError)

我确实看到checks that RSpec runs(追溯from where the RSpec::Mocks::MockExpectationError gets thrown)至少正确地报告了他们从班级获得的信息:

[1] pry(main)> require 'aws-sdk'
=> true
[2] pry(main)> klass = AWS::AutoScaling::Client
=> AWS::AutoScaling::Client
[3] pry(main)> klass.public_method_defined? "update_auto_scaling_group"
=> false
[4] pry(main)> klass.private_method_defined? "update_auto_scaling_group"
=> false
[5] pry(main)> klass.protected_method_defined? "update_auto_scaling_group"
=> false

然而,如果我们问一个实际的实例,它会让我们知道这是一个它会响应的方法:

[6] pry(main)> x = klass.new
=> #<AWS::AutoScaling::Client::V20110101>
[7] pry(main)> x.respond_to? "update_auto_scaling_group"
=> true

即使它没有说任何事情:

[8] pry(main)> x.respond_to? "bogus"
=> false

第一个问题:

所以...这是the AWS::AutoScaling::Client code(或者真的,可能是here)中的一个错误,因为没有以现有检查({public,private,protected}_method_defined?)来定义方法回到真的吗?

或许是RSpec的“双打”中的一个错误,因为没有做所有的检查,试图找出这确实是一个可以在该类的实例中调用的方法?

或许这只是我在这里做错的事情?其他

更一般地说:

我如何为我正在编写的代码编写测试,以确保它使用正确的参数(如我在几个检查中定义的那样)调用AWS::AutoScaling::Client实例。我是否有其他方法可以编写可以使其工作的步骤定义?创建我的模拟对象的其他方法?其他

3 个答案:

答案 0 :(得分:1)

我找到了一种动态混合模拟

所需方法的方法

您可以使用空方法执行此操作,然后将它们存根,或者只在stubin中包含存根

Sub ReplaceValues
    Dim ws1 As Worksheet
    Dim ws2 As Worksheet
    Dim rows1 As Long
    Dim rows2 As Long

    Dim row1 As Long
    Dim row2 As Long

    Set ws1 = Worksheets("Sheet1")
    Set ws2 = Worksheets("Sheet2")

    rows1 = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Row
    rows2 = ws2.Range("A" & ws2.Rows.Count).End(xlUp).Row

    For row1 = 1 To rows1
        For row2 = 1 To rows2
            ws1.Cells(row1, 1).Value = Replace(ws1.Cells(row1, 1).Value, _
                                               ws2.Cells(row2, 1).Value, _
                                               ws2.Cells(row2, 2).Value)
        Next
    Next
End Sub

答案 1 :(得分:0)

它只是在实例化时/之后添加方法。它非常合法,所有红宝石类/对象都是开放的。

正确答案 - 您不希望使用开放类和对象测试您尝试使用duck-typed语言测试的内容。它没有意义。

答案 2 :(得分:0)

适用于Ruby的第1版AWS开发工具包使用#method_missing作为构建和发送请求的委托。客户端响应的方法在API定义中定义。这样可以消除样板代码,但如果您试图在运行时反映可用的方法,则会导致问题。

选项A:使用常规double并在测试双精度上应用断言。

选项B:通过AWS.stub使用SDK的模拟功能!启用存根时,构造的所有客户端都将响应其常规方法,但将返回虚拟响应(空哈希和数组)。此方法提供了指定从存根返回的数据的有用功能。您甚至可以创建存根响应,以明确从断言返回。

选择B:

# use `:stub_requests` or call Aws.stub!
as = AWS::AutoScaling::Client.new(:stub_requests: true)

# validates parameters as normal, but returns empty response data
as.update_auto_scaling_group(auto_scaling_group_name: 'name')
#=> {}

# You can access the stub response for any operation by name:
stub = as.stub_for(:describe_auto_scaling_groups)
stub.data[:auto_scaling_group_names] = ["Group1", "Group2"]

# Now calling that operation will return the stubbed data
resp = as.describe_auto_scaling_groups
resp.auto_scaling_group_names
#=> ['Group1', 'Group2']

如果需要断言对客户端调用方法,则可以正常执行,返回存根响应:

expect(@client).to receive(:describe_auto_scaling_groups).
  with(hash_including(param, value)).
  and_return(@client.stub_for(:describe_auto_scaling_groups))