admin管理员组文章数量:1122832
Working with rspec-expectations 3.13.3 and have code such as:
def methname(**kwargs)
# let's assume this method doesn't mind whether the kwargs are keyed by symbols or strings
p(received: kwargs)
end
with a test such as
expect(something).to receive(:methname).with(hash_including(what_ever: "else"))
But in some cases the keyword arguments are being created as strings, not symbols, so that fails and I have to do
expect(something).to receive(:methname).with(hash_including("what_ever" => "else"))
I can get this right in each spec, but it would be cleaner for me if I could match it indifferently -
# desired code
expect(something).to receive(:methname).with(hash_including_indifferently(what_ever: "else"))
is there a way to already do this?
Working with rspec-expectations 3.13.3 and have code such as:
def methname(**kwargs)
# let's assume this method doesn't mind whether the kwargs are keyed by symbols or strings
p(received: kwargs)
end
with a test such as
expect(something).to receive(:methname).with(hash_including(what_ever: "else"))
But in some cases the keyword arguments are being created as strings, not symbols, so that fails and I have to do
expect(something).to receive(:methname).with(hash_including("what_ever" => "else"))
I can get this right in each spec, but it would be cleaner for me if I could match it indifferently -
# desired code
expect(something).to receive(:methname).with(hash_including_indifferently(what_ever: "else"))
is there a way to already do this?
Share Improve this question edited Nov 22, 2024 at 19:22 Tim Diggins asked Nov 22, 2024 at 12:20 Tim DigginsTim Diggins 4,5063 gold badges31 silver badges50 bronze badges 3- @engineersmnky FYI this is testing what methname receives, not what it outputs. Have updated the question – Tim Diggins Commented Nov 22, 2024 at 19:19
- This sounds like you should be normalizing your inputs instead of making your method deal with whatever garbage you toss at it. Passing string keys as keywords arguments defeats the whole point as you can only access them through the keywords hash. – max Commented Nov 23, 2024 at 12:25
- If you have to accept that kind of input do it through a postitional argument instead so that your intent is clear. – max Commented Nov 23, 2024 at 12:33
1 Answer
Reset to default 0Is there a way to already do this?
There is no built in matcher that supports this but we can use built in matchers to accomplish this goal (for single use) or create our own matcher (multi-use).
Solution
If you need this frequently or need it to be more flexible in what is or is not included in the Hash
, your best bet is to define your own matcher. See: Custom Matchers.
For Example this will work:
RSpec::Matchers.define_negated_matcher :not_include, :include
RSpec::Matchers.define :indifferently_include do |expected|
match(:notify_expectation_failures => true) do |actual|
fit_pattern = expected.map do |k,v|
include(k.to_s).and(not_include(k.to_sym)).or(
include(k.to_sym).and(not_include(k.to_s))
).and(
include(k.to_s => v).or(include(k.to_sym => v))
)
end.reduce(&:and)
expect(actual).to fit_pattern
end
end
RSpec::Matchers.alias_matcher :hash_including_indifferently, :indifferently_include
Usage:
expect(something).to receive(:methname).with(hash_including_indifferently({"what_ever" => "else", another_key: "too"}))
Methodology
If you want to test in such a way as to allow kwargs
to contain either of {"what_ever" => "else"}
or {what_ever: "else"}
you can test as follows:
expect(something).to receive(:methname) do |h|
expect(h).to include(what_ever: "else").or include("what_ever" => "else")
end
because receive
with a block will yield the arguments to the block and you can test them explicitly using a Compound Expectation.
However if the Hash
contains both :what_ever
and "what_ever"
as keys as long as one of them has the value "else"
this test will pass. Given that your intent is for this test to be indifferent about whether the key is a String
or Symbol
, the keys would need to be uniquely indifferent as well, so you may want to test as:
RSpec::Matchers.define_negated_matcher :not_include, :include
expect(something).to receive(:methname) do |h|
expect(h).to include("what_ever").and(
not_include(:what_ever)
).or(
include(:what_ever).and(
not_include("what_ever")
)
).and(
include("what_ever" => "else").or(
include(what_ever: "else")
)
)
end
This will prevent ambiguity for any Hash
that might contain both "what_ever"
and :what_ever
keys, while ensuring that one of them is present with the value "else"
.
本文标签:
版权声明:本文标题:ruby - Is there a way to set up an expectation for a hash but being "indifferent" about whether keys are symbo 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736303808a1932010.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论