I'm writing a test in MiniTest to the app which uses Devise and I have a little (I hope) problem.
I want to check if the user's password is correct. There is a method
valid_password?(password) called on a particular user which does what I need.
But my problem is that in this app this method is overwritten in that way:
def valid_password?(password)
if condition
# some else code
else
super
end
end
Is there any possibility to use valid_password? from super (Devise) in the unit tests?
Thanks in advance for any help.
There are some "hacky" ways that you could achieve this, but the rightâ„¢ way to do this is to structure your test such that condition is falsey. The way to do this, of course, depends on how condition is defined!
For example, suppose the method is implemented as:
def condition(password)
password.length < 10
end
In that case, you should simply run the test with a long password.
You could also (as a last resort) stub the condition method to return false - but this is bad practice. Your test would then not be a reflection of reality, since the actual circumstances under which super is being executed may not be fulfilled.
Related
I'm writing a Rspec test for existing code that I've added some logic to that I want to ensure is working properly. I do not care about the returned values, just that the logic works on an object that I pass to it. For simplicity here is an example of very a basic function from within a class I have built:
def function_I_want_to_test(thing)
if thing > 0
function_a(thing)
else
function_b(thing)
end
end
function_a and function_b already have spec tests, so I don't really care what the return values are, but both function_a and function_b make API calls which I feel would make the rspec test a lot more complicated for testing only the logic contained within function_I_want_to_test.
I've gone through this page (https://blog.codeship.com/unit-testing-in-ruby/) reviewing the unit testing approach, and the explanations make sense, but when attempting to use allow and receive, it appears that the function is still wanting to be called so I'm assuming I'm not utilizing the functions correctly.
Essentially I want to treat my code as such, and have it return something arbitrary so it doesn't even call the function.
def function_I_want_to_test(thing)
if thing > 0
pp "a"
else
pp "b"
end
end
From my research, it appears the allow/expect is the way to go, but I'm assuming I'm not fully understanding the concept.
I guess the main question I have is, how does my rspec test know to "override" the functions (function_a and function_b) when testing function_I_want_to_test?
I know there are a few similar asked questions, but they didn't seem to answer how I was anticipating.
I am working through Learn Ruby The Hard Way and came across something intriguing in exercise 49.
In parser.rb I have a function named skip(word_list, word_type) at the top level, which is used to skip through unrequited words (such as stop words) in user input. It is not encapsulated in a class or module. As per the exercise I have to write a unit test for the parser.
This is my code for the Unit Tests:
require "./lib/ex48/parser"
require "minitest/autorun"
class TestGame < Minitest::Test
def test_skip()
word_list = [['stop', 'from'], ['stop', 'the'], ['noun', 'west']]
assert_equal(skip(word_list, 'stop'), nil)
assert_equal(skip([['noun', 'bear'], ['verb', 'eat'], ['noun', 'honey']], 'noun'), nil)
end
end
However, when I run rake test TESTOPTS="-v" from the command line, these particular tests are skipped. This seems to be because there is a clash with the skip method in the Minitest module because they run perfectly after I change the name to skip_words.
Can someone please explain what is going on here exactly?
"Top level functions" are actually methods too, in particular they are private instance methods on Object (there's some funkiness around the main object but that's not important here)
However minitest's Test class also has a skip method and since the individual tests are instance methods on a subclass of Test you end up calling that skip instead.
There's not a very simple way of dealing with this - unlike some languages there is no easy way of saying that you want to call a particular superclass' implementation of something
Other than renaming your method, you'll have to pick an alternative way of calling it eg:
Object.new.send(:skip, list, type)
Object.instance_method(:skip).bind(self).call(list, type)
Of course you can wrap this in a helper method for your test or even redefine skip for this particular Test subclass (although that might lead to some head scratching the day someone tries to call minitest's skip.
I'm learning rspec, and I'm wondering what the most effective way to write specs for a method that calls a chain of other methods. For example:
class Example1
def foo(dependency)
dependency.bar("A")
dependency.baz("B")
dependency.bzz("C")
end
end
Ideally I would like to write specs like this:
it "should call bar" do
ex = Example1.new
dep = mock
dep.should_receive(:bar).with("A")
ex.foo(dep)
end
it "should call baz"
...
it "should call bzz"
...
When I do that, however, I (understandably) get exceptions like 'unexpected method call baz'.
So what's the best way to deal with that? I have come up with a couple of ideas but I don't know if any of them are good.
Make the mock dependency an "as_null_object" so it ignores the extra calls. (Down side - if I was calling unwanted random stuff on that object, I wouldn't know it)
Stub out the two unused dependency method calls in each spec (Down side - feels very DRY)
Stub out all three dependency calls in a 'before' (Down side - puts a lot of junk in the 'before')
It sounds like you have already worked out which options RSpec gives you. I would go with option 1 and use as_null_object. It's true that you might be missing other random method calls on that object but I would be ok with that if the point of each of these tests was simply to assert that a particular method was being called, especially if I have higher level integration tests covering this method.
If you really need to verify that no other methods are called on dependency then option 3 may make sense but such tests can be brittle when implementation changes.
As an aside, to make your test a little simpler you can use subject to avoid explicitly instantiating Example1 (assuming you are using a describe Example1 block), e.g.:
subject.foo(dep)
(However see discussion in comments - an implicit subject can hide intention).
RSpec has a feature called stub_chain: https://www.relishapp.com/rspec/rspec-mocks/v/2-0/docs/stubs/stub-a-chain-of-methods
What about testing them all in one example?
it "should call bar"
ex = Example1.new
dep = mock
dep.should_receive("bar").with("A")
dep.should_receive("baz").with("B")
dep.should_receive("bzz").with("C")
ex.foo(dep)
end
I believe you can use RSpec to verify the order in which they are called, if that matters.
However, this kind of approach often indicate that there is a problem with how the code is written, e.g. a Law Of Demeter violation. In your example, foo should be a methed on the dependency's class.
I would test this code in this way:
describe "checking foo method" do
before(:each) do
#ex = Example1.new
#test = ClassOfDependency.any_instance
#test.as_null_object
end
after(:each) do
#ex.foo(dependency)
end
it "should call bar method" do
#test.should_receive(:bar).with("A")
end
it "should call baz method" do
#test.should_receive(:baz).with("B")
end
it "should call bzz method" do
#test.should_receive(:bzz).with("C")
end
end
But I'm not sure that it will work, hope it'll give you some ideas.
I'm trying to stub any instance of some class. I need to stub the fetch method, which fills the self with some data.
How can I get access to self variable, modify it and return on fetch method?
MyObject.any_instance.stub(:fetch) { self }
doesn't return a MyObject instance.
Maybe, mocks is more useful in this situation. Unfortunately, I haven't understood they yet.
There's an open rspec-mocks issue to address this. I hope to get around to addressing it at some point, but it's not simple to add this in a way that doesn't break existing spec suites that use any_instance with a block implementation, because we would start yielding an additional argument (e.g. the object instance).
Overall, any_instance can come in handy in some situations, but it's a bit of a smell, and you'll generally have fewer issues if you can find a way to mock or stub individual instances.
Here's a work around that I have not tested but should work:
orig_new = MyObject.method(:new)
MyObject.stub(:new) do |*args, &block|
orig_new.call(*args, &block).tap do |instance|
instance.stub(:fetch) { instance }
end
end
Essentially, we're simulating any_instance here by hooking into MyObject.new so that we can stub fetch on each new instance that is instantiated.
All that said, it's important to "listen to your tests", and, when something is hard to test, consider what that says about your design, rather than immediately using power tools like any_instance. Your original question doesn't give enough context for me to speculate anything about your design, but it's definitely where I would start when faced with a need to do this.
As far as I can see it, this doesn't seem to be possible, for some reason. I checked the current rspec-mocks implementation, and the method actually invoking the stub implementation seems to be the following:
# lib/rspec/mocks/message_expectation.rb:450
def call_implementation(*args, &block)
#implementation.arity == 0 ? #implementation.call(&block) : #implementation.call(*args, &block)
end
As it seems, the block is simply invoked by itself and not through instance_eval. Maybe there is another technique to achieve what you want though, after all I am not an RSpec expert by any means.
I'm adding unit tests to a large batch of code and am looking for a way to insert fake methods in for testing purposes. The problem is that, as far as I know in Ruby, to pass a method in one must use ClassName.method(:method_name), and then refactor the method I'm testing to use boo.call() instead of just boo(). Is there an easier way to do this than refactoring everything to use .method and .call?
Why not just pass lambdas? I mean, lambda is just an anonymous method/function as you know it from other languages, so it should work fine. Eg:
fake_method = lambda { |n| "do something with n" }
def other_method(fm)
#...
fm.call
#...
end
other_method(fake_method)
You still need to call .call though