I have a function I'm calling that I need to test the arguments of. Normally I'd do something like:
expect(my_obj).to_receive(:my_function).with(include('good_value'))
Is there a way to flip this around, though, to be something like
expect(my_obj).to_receive(:my_function).with(exclude('bad_value'))
In a spec on a return value this is simply accomplished using to_not, but that form of negation is not available when matching arguments it seems. I can find nothing in the docs suggesting a way to do this other than writing a custom matcher, which feels like overkill here.
Is there a simple way I can do this without having to write a custom matcher?
RSpec 3.1+ allows you to define a negated version of any matcher using RSpec::Matchers.define_negated_matcher:
RSpec::Matchers.define_negated_matcher :exclude, :include
Once you've done that, this should work:
expect(my_obj).to_receive(:my_function).with(exclude('bad_value'))
You may try:
http://www.rubydoc.info/gems/rspec-mocks/RSpec/Mocks/ArgumentMatchers#hash_excluding-instance_method
expect(object).to receive(:message).with(hash_excluding(:key => val))
Related
Consider the following Ruby expression:
y=x.a.b.c.d.e.f
Of course, x is an object and a to f are methods defined for a class which matches the return value of the previous method in the chain. Now say that I want to replace the invocation of method c by a custom block, i.e. I would like to achieve the effect of
temp=x.a.b
temp1=.... (calculate something based on the value of temp)
y=temp1.d.e.f
but with using method chaining.
It is of course trivial to define a suitable method to achieve this:
class Object
def pass
yield(self)
end
end
which would allow me to write something like
y=x.a.b.pass {|the_b| .....}.d.e.f
Now to my question:
Given that Ruby already has a method for a similar problem (Object#tap), I wonder why it does not have a method similar to the Object#pass which I just explained. I suspect, that either
(a) Ruby already offers a feature like this, and I'm just to stupid to find it, or
(b) What I want to achieve would be considered bad programming style (but then, why?)
Is (a) or (b) correct, or did I miss something here?
(a) Yes. Ruby already has that. It is called yield_self.
(b) No. It is not a bad style.
In ERB or HAML, I need to be able to evaluate one function, or a different one, based on the output of a conditional, while using the same HTML block for either one.
In HAML, it would like something like this:
- is_a = #thing.is_a?
= (is_a ? f.method_a : f.method_b) arg_1, |block_arg1| do
#thing
.blah
.inner-thing
= block_arg1.some_method
Notice how, on line 2 of my pseudocode, I am trying to evaluate either one function, or the other, based upon a conditional. But I need pass the same arguments to either, especially since I don't want to have to re-type the DO block.
Maybe I could avoid that problem ("I don't want to re-type...") by making that DO block a named function? How does one turn a HAML or ERB block into a named Ruby function?
I'm using Ruby-on-Rails 4. Not that it matters; this looks like more of a ruby syntax question than a framework question.
You seem to be looking for #send
- is_a = #thing.is_a?
= f.send(is_a ? :method_a : :method_b, arg_1) do |block_arg|
(...)
Not sure if this is possible but can I call a method from an irb shell with spaces between parameters rather than commas (don't ask) ? Lets say I have a method
def start_band(member1, member2, member3, member4)
#do something
end
And then I call it like the following:
irb>> start_band "John" "Paul" "George" "Ringo"
EDIT: Would it be possible to detect every keypress instead?
No, you can't do that. Not with strings anyway.
No.
You could use something like treetop to write a really simple DSL, or just play monkey-parsing games, but that won't solve your exact question.
The other obvious answer is this, which also fails:
irb>> start_band %W(John Paul George Ringo)
Creating an irb-like CLI isn't difficult, and may be adequate, depending on what your actual requirements are.
There is actually a very easy way to get rid of the commas. You can even get rid of the quotes, too:
def start_band(members)
#members is an array
end
start_band %w(John Paul George Ringo)
The limitation is that you can't use spaces inside your strings, and you still need start-end terminations (can use other characters instead of parenthesis though).
Durr! I really approached this the wrong way. I simply needed to run
#members = gets
to allow the input as required. Thanks for the responses nonetheless.
What would be the best way to write the rspec in a situation where either of two (or more) outcomes are acceptable?
Here's an example of what I want to do. This is obviously wrong (I think), but it should give you the gist of what I'm trying to accomplish:
it "should be heads or tails" do
h="heads"
t="tails"
flip_coin.should be(h || t)
end
And yes, I'm aware I could write my own rspec matcher "should_be_one_or_the_other(option1,option2)", but that seems a bit much - I was hoping for a better solution.
ActiveSupport provides Object#in? method. You can combine it with RSpec and simply use the following:
flip_coin.should be_in(["heads", "tails"])
Or with new Rspec 3 syntax:
expect(flip_coin).to be_in(["heads", "tails"])
I know this is old but in I ran into this on RSpec 3.4, there is an or method now. So this is valid:
expect(flip_coin).to eq('heads').or(eq('tails'))
I'd probably write something like this:
it "should be heads or tails" do
["heads", "tails"].should include flip_coin
end
Another way of writing it with the expectation on the right of the should:
it 'should be heads or tails' do
flip_coin.should satisfy{|s| ['heads', 'tails'].include?(s)}
end
if applied or with be matcher
expect(flip_coin).to eq('heads').or(be == 'tails')
You can solve this by flipping the comparison:
expect(['head','tails']).to include(flip_coin)
I have a method named RenderContent which returns object[]
In my unit test, I need to assert that this array does not contain any objects of type VerifyRequest
At the moment, I'm using the following Assert statement. Is there anything more concise?
Assert.That(
domain.RenderContent().OfType<VerifyRequest>().Count(),
Is.EqualTo(0)
);
I prefer to use fluent syntax. Note also that RenderContent returns object[], not IQueryable<object>.
If you are using NUnit 2.5, you could use something like:
Assert.That(domain.RenderContent(), Has.None.InstanceOf<VerifyRequest>());
But I'm not sure if other unit test frameworks support this assert-style.
Although I don't know the exact NUnit syntax for IsFalse assertion, the best fit for this kind of test is the Any extension method:
Assert.IsFalse(domain.RenderContent().OfType<VerifyRequest>().Any());
It might be tempting to use the Count method, but Any is more efficient, as it will break on the first occurrence.
The Any extension method, which can be given a lambda expression:
Assert.IsFalse(domain.RenderContent().Any(i => i is VerifyRequest));
You could shorten it a tad by using the Assert.AreEqual method instead:
Assert.AreEqual(domain.RenderContent().OfType<VerifyRequest>().Count(), 0);
I prefer the Assert.AreEqual approach; NUNit uses Assert.That for the internal Assert, STringAssert, etc objects. I like just doing Assert.AreEqual(0, domain.RenderContent().OfType().Count()); to check for the counts.
This way, it checks directly that no objects of a type have any number of records, but to a point the variations you see are preference and they all are equally valid. You have to choose what you like for your style of development.