Rspec for checking of a number - ruby

I am a ruby newbie, I have managed to pull out the code for ruby but writing rspecs for them seems problematic. It's hard to understand the way to write rspecs even after reading few tutorials. Someone please help me to write for an input method then I would try to refactor it for the rest.
RB file:
module RubyOperations
class Operations
def input(num)
RubyOperations.log('Enter a number:[Between 1 to 10]',:BOTH)
num = Integer(gets.chomp)
raise StandardError if num <= 0 || num > 10
return num
rescue StandardError, ArgumentError => e
RubyOperations.log(e,:ERROR)
end
end
end
RSPEC:
describe 'RubyOperations' do
describe 'Operations' do
describe '.input' do
context 'when number is provided' do
it 'returns the number provided' do
expect(RubyOperations.input(num)).to eq(Integer)
end
end
end
end
end

You can check the class of the output of the method to equal integer
require 'ruby_final_operations'
describe 'RubyOperations' do
describe 'Operations' do
describe '.input' do
context 'when number is provided' do
it 'returns the number provided' do
expect(RubyOperations.input(num).class).to eq(Integer)
(or)
expect(RubyOperations.input(num)).to be_a_kind_of(Integer)
end
end
end
end
end
And whenever you write rspec keep in mind
If the method for which you are writing rspec deals with manipulations in your db then check if db is manipulated or not
Or if you are writing rspec for any methods which returns an object then procced like this
if a method is defined like
def square_of_a_number(num)
num*num
end
Then write rspec like this
it 'returns square of a number' do
expect(square_of_a_number(2).to eq(4)
end
For any methods that you know the output of a method will be that then hardcode the input or user Faker gem for input of the method expect the expected result of that method

There are few issues with code that you have shared:
1) In the Operations class, the method input receives an argument which is not used anywhere because of this line: num = Integer(gets.chomp). Basically gets is the method that waits for user input, and the assignment num = ... overrides the value of argument (num) that is passed into the method, hence it is pointless to pass num argument into the method.
2) In your spec sample you call input method on RubyOperations module, while the input lives in class Operations under namespace RubyOperations. Also method input is not a class method but instance method. So proper method call would be: RubyOperations::Operations.new.input(5)
3) To run a spec for input method you would need to stub user input. RSpec-mocks gem can help you with that - https://github.com/rspec/rspec-mocks. It has allow stub method: allow(object).to receive(:gets) { "5" }
The whole sample will be:
it 'returns the number provided' do
# instantiate object that we will test
subject = RubyOperations::Operations.new
# we stub method 'gets' and whenever it is called we return string "5"
allow(subject).to receive(:gets) { "5" }
# we call method input with argument 1, the argument 1 is pointless as described in point 1) and can be omitted
expect(subject.input(1)).to eq(5)
end

Related

Ruby/Minitest Spec: How to test that a method returns a value within a given array?

I have the following class:
class State
def self.alive
:alive
end
def self.dead
:dead
end
end
Testing is simple:
it 'should report the expected state for alive' do
State.alive.must_equal :alive
end
it 'should report the expected state for dead' do
State.dead.must_equal :dead
end
I want to add a class method which returns a random state.
class State
# ...
def self.random
[alive, dead].sample
end
However, I'm unsure of which assertion I need to use.
Currently, I am testing it as follows:
it 'should return a random state' do
%i[dead alive].must_include State.random
end
Which is back to front. The test above is testing the literal array rather that the State class.
Is there a better way to test that a method returns a value included within a specified array?
Before I offer you a solution, I want to unravel some details about the Spec DSL and Minitest. The must_include methods is the Spec DSL expectation for the assert_includes assertion. That method has the following signature:
assert_includes collection, obj, msg = nil
When the expectation is created, the signature is:
Collection#must_include obj, msg = nil
So what you are really asking is for a way of calling these methods with the argument order reversed. This is pretty simple to do by creating new methods that use your desired argument order. First, we must create the assertion:
module Minitest::Assertions
##
# Fails unless +obj+ is included in +collection+.
def assert_included_in obj, collection, msg = nil
msg = message(msg) {
"Expected #{mu_pp(obj)} to be included in #{mu_pp(collection)}"
}
assert_respond_to collection, :include?
assert collection.include?(obj), msg
end
end
Now that we have the assertion method, we can create the Spec DSL expectation:
module Minitest::Expectations
##
# See Minitest::Assertions#assert_included_in
#
# collection.must_be_one_of obj
#
# :method: must_be_one_of
infect_an_assertion :assert_included_in, :must_be_one_of, :reverse
end
Now that we have defined the expectation, and the assertion it uses, we can use it in the test:
it "should return a random state" do
State.random.must_be_one_of %i[dead alive]
end
I would take it one step further, and use the value monad to call the expectation:
it "should return a random state" do
value(State.random).must_be_one_of %i[dead alive]
end

Stub a function which is inside the function to be tested

I have a function let's say A whose output and functionality I have to test, A calls another function B which takes a lot of time to compute the output. So I am trying to use stubs to mimic all the values that B returns.
def A
#do something
output = B
#do something with output
end
Now the test files
describe "check what A returns" do
ClassName.stub(:B) do
[0, 1]
end
test_values = TestClass.A(input parameters)
#checks on test values
end
My aim is to pass the expected output of B to function A. I am using RSpec. How do I go about it?
With RSpec you can do:
allow(ClassName).to receive(:B).and_return([1,2,3,4,5])
After this you can call B function and it will return [1,2,3,4,5]
You can find more info at RSpec documentation: https://relishapp.com/rspec/rspec-mocks/v/3-4/docs/configuring-responses/returning-a-value
I've attempted to write some classes and test cases for what it seems like you want to test. The key here is to use allow to stub out the return value for a method.
Just note here that I've changed the methods in your class to be class methods to fit what seems to be your test case, but you can obviously change them back to instance methods to fit your purpose. Also, accepted Ruby style is to have lowercase method names.
class ClassName
def self.B
# returns something that we're going to stub out
end
end
class TestClass
def self.A
# do something
output = ClassName.B
# do something with output
# eg in this case, add a value to it
output << 2
end
end
describe TestClass do
describe '.A' do
before do
allow(ClassName).to receive(:B).and_return([0, 1])
end
it 'does something with output' do
expect(described_class.A).to eq([0, 1, 2])
end
end
end
There's ways as mentioned in other posts but I'll give you another: you might want to make that dependency explicit.
Here's how it could look like:
# test_class.rb
class TestClass
# The default will be automatically setup to be an object of type ClassName
def initialize(some_collaborator: ClassName.new)
self.some_collaborator = some_collaborator # Some people will probably also insert some guard (to make sure it responds to `b`
end
def a
# your code calling `some_collaborator.b`
end
private
attr_accessor :some_collaborator
end
# test_class_spec.rb
describe TestClass do
let(:stub_b) { stub("Some instance of ClassName", b: [...] }
subject { TestClass.new(some_collaborator: stub_b) }
it "whatever" do
expect(subject.a).to ...
end
end
The default collaborator should be a sensible default (and if you can't instantiate it there's ways to encapsulate it anyways). Not only it will be easier to read, but it will be easier to maintain.

Why is this Ruby conditional assignment not memoized?

Can someone explain why this spec is failing?
RSpec results:
User#presenter memoizes presenter
Failure/Error: user.presenter
(<UserPresenter (class)>).new(...)
expected: 1 time with any arguments
received: 2 times with arguments: (...)
From my understanding of the conditional assignment operator it should only assign #presenter once.
# app/models/user.rb
def User
def presenter
#presenter ||= UserPresenter.new(self)
end
end
# app/presenters/user_presenter.rb
class UserPresenter
end
# spec/models/user_spec.rb
describe User do
let(:user){ build_stubbed(:user) }
describe "#presenter" do
it "memoizes presenter" do
UserPresenter.should_receive(:new).once
user.presenter
user.presenter # should not call .new
end
end
end
The issue is this line:
UserPresenter.should_receive(:new).once
This chunk of code simply sets up the expectation that a UserPresenter will receive the new method one time. It tears down your original UserPresenter#new method and replaces it with a method that returns nil. Because nil is falsy, the #presenter instance variable is not memoized.
To fix this, you can specify a return value in your expectation:
UserPresenter.should_receive(:new).once.and_return "some truthy value"
or equivalently
UserPresenter.should_receive(:new).once { "some truthy value" }
or if you absolutely want to call the original method
UserPresenter.should_receive(:new).once.and_call_original
or with the new expect syntax
expect(UserPresenter).to receive(:new).once.and_call_original
See this for more information about expecting a message, and this for more information about calling the original method. This has some further discussion about RSpec's should_receive method.

Blocks and yields in Ruby

I am trying to understand blocks and yield and how they work in Ruby.
How is yield used? Many of the Rails applications I've looked at use yield in a weird way.
Can someone explain to me or show me where to go to understand them?
Yes, it is a bit puzzling at first.
In Ruby, methods can receive a code block in order to perform arbitrary segments of code.
When a method expects a block, you can invoke it by calling the yield function.
Example:
Take Person, a class with a name attribute and a do_with_name method. When the method is invoked it will pass the name attribute to the block.
class Person
def initialize( name )
#name = name
end
def do_with_name # expects a block
yield( #name ) # invoke the block and pass the `#name` attribute
end
end
Now you can invoke this method and pass an arbitrary code block.
person = Person.new("Oscar")
# Invoking the method passing a block to print the value
person.do_with_name do |value|
puts "Got: #{value}"
end
Would print:
Got: Oscar
Notice the block receives as a parameter a variable called value. When the code invokes yield it passes as argument the value of #name.
yield( #name )
The same method can be invoked with a different block.
For instance to reverse the name:
reversed_name = ""
# Invoke the method passing a different block
person.do_with_name do |value|
reversed_name = value.reverse
end
puts reversed_name
=> "racsO"
Other more interesting real life examples:
Filter elements in an array:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Select those which start with 'T'
days.select do | item |
item.match /^T/
end
=> ["Tuesday", "Thursday"]
Or sort by name length:
days.sort do |x,y|
x.size <=> y.size
end
=> ["Monday", "Friday", "Tuesday", "Thursday", "Wednesday"]
If the block is optional you can use:
yield(value) if block_given?
If is not optional, just invoke it.
You can try these examples on your computer with irb (Interactive Ruby Shell)
Here are all the examples in a copy/paste ready form:
class Person
def initialize( name )
#name = name
end
def do_with_name # expects a block
yield( #name ) # invoke the block and pass the `#name` attribute
end
end
person = Person.new("Oscar")
# Invoking the method passing a block to print the value
person.do_with_name do |value|
puts "Got: #{value}"
end
reversed_name = ""
# Invoke the method passing a different block
person.do_with_name do |value|
reversed_name = value.reverse
end
puts reversed_name
# Filter elements in an array:
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
# Select those which start with 'T'
days.select do | item |
item.match /^T/
end
# Sort by name length:
days.sort do |x,y|
x.size <=> y.size
end
In Ruby, methods can check to see if they were called in such a way that a block was provided in addition to the normal arguments. Typically this is done using the block_given? method but you can also refer to the block as an explicit Proc by prefixing an ampersand (&) before the final argument name.
If a method is invoked with a block then the method can yield control to the block (call the block) with some arguments, if needed. Consider this example method that demonstrates:
def foo(x)
puts "OK: called as foo(#{x.inspect})"
yield("A gift from foo!") if block_given?
end
foo(10)
# OK: called as foo(10)
foo(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as foo(123)
# BLOCK: A gift from foo! How nice =)
Or, using the special block argument syntax:
def bar(x, &block)
puts "OK: called as bar(#{x.inspect})"
block.call("A gift from bar!") if block
end
bar(10)
# OK: called as bar(10)
bar(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as bar(123)
# BLOCK: A gift from bar! How nice =)
It's quite possible that someone will provide a truly detailed answer here, but I've always found this post from Robert Sosinski to be a great explanation of the subtleties between blocks, procs & lambdas.
I should add that I believe the post I'm linking to is specific to ruby 1.8. Some things have changed in ruby 1.9, such as block variables being local to the block. In 1.8, you'd get something like the following:
>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"
Whereas 1.9 would give you:
>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"
I don't have 1.9 on this machine so the above might have an error in it.
I found this article to be very useful. In particular, the following example:
#!/usr/bin/ruby
def test
yield 5
puts "You are in the method test"
yield 100
end
test {|i| puts "You are in the block #{i}"}
test do |i|
puts "You are in the block #{i}"
end
which should give the following output:
You are in the block 5
You are in the method test
You are in the block 100
You are in the block 5
You are in the method test
You are in the block 100
So essentially each time a call is made to yield ruby will run the code in the do block or inside {}. If a parameter is provided to yield then this will be provided as a parameter to the do block.
For me, this was the first time that I understood really what the do blocks were doing. It is basically a way for the function to give access to internal data structures, be that for iteration or for configuration of the function.
So when in rails you write the following:
respond_to do |format|
format.html { render template: "my/view", layout: 'my_layout' }
end
This will run the respond_to function which yields the do block with the (internal) format parameter. You then call the .html function on this internal variable which in turn yields the code block to run the render command. Note that .html will only yield if it is the file format requested. (technicality: these functions actually use block.call not yield as you can see from the source but the functionality is essentially the same, see this question for a discussion.) This provides a way for the function to perform some initialisation then take input from the calling code and then carry on processing if required.
Or put another way, it's similar to a function taking an anonymous function as an argument and then calling it in javascript.
I wanted to sort of add why you would do things that way to the already great answers.
No idea what language you are coming from, but assuming it is a static language, this sort of thing will look familiar. This is how you read a file in java
public class FileInput {
public static void main(String[] args) {
File file = new File("C:\\MyFile.txt");
FileInputStream fis = null;
BufferedInputStream bis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream(file);
// Here BufferedInputStream is added for fast reading.
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
// dis.available() returns 0 if the file does not have more lines.
while (dis.available() != 0) {
// this statement reads the line from the file and print it to
// the console.
System.out.println(dis.readLine());
}
// dispose all the resources after using them.
fis.close();
bis.close();
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Ignoring the whole stream chaining thing, The idea is this
Initialize resource that needs to be cleaned up
use resource
make sure to clean it up
This is how you do it in ruby
File.open("readfile.rb", "r") do |infile|
while (line = infile.gets)
puts "#{counter}: #{line}"
counter = counter + 1
end
end
Wildly different. Breaking this one down
tell the File class how to initialize the resource
tell the file class what to do with it
laugh at the java guys who are still typing ;-)
Here, instead of handling step one and two, you basically delegate that off into another class. As you can see, that dramatically brings down the amount of code you have to write, which makes things easier to read, and reduces the chances of things like memory leaks, or file locks not getting cleared.
Now, its not like you can't do something similar in java, in fact, people have been doing it for decades now. It's called the Strategy pattern. The difference is that without blocks, for something simple like the file example, strategy becomes overkill due to the amount of classes and methods you need to write. With blocks, it is such a simple and elegant way of doing it, that it doesn't make any sense NOT to structure your code that way.
This isn't the only way blocks are used, but the others (like the Builder pattern, which you can see in the form_for api in rails) are similar enough that it should be obvious whats going on once you wrap your head around this. When you see blocks, its usually safe to assume that the method call is what you want to do, and the block is describing how you want to do it.
In Ruby, a block is basically a chunk of code that can be passed to and executed by any method. Blocks are always used with methods, which usually feed data to them (as arguments).
Blocks are widely used in Ruby gems (including Rails) and in well-written Ruby code. They are not objects, hence cannot be assigned to variables.
Basic Syntax
A block is a piece of code enclosed by { } or do..end. By convention, the curly brace syntax should be used for single-line blocks and the do..end syntax should be used for multi-line blocks.
{ # This is a single line block }
do
# This is a multi-line block
end
Any method can receive a block as an implicit argument. A block is executed by the yield statement within a method. The basic syntax is:
def meditate
print "Today we will practice zazen"
yield # This indicates the method is expecting a block
end
# We are passing a block as an argument to the meditate method
meditate { print " for 40 minutes." }
Output:
Today we will practice zazen for 40 minutes.
When the yield statement is reached, the meditate method yields control to the block, the code within the block is executed and control is returned to the method, which resumes execution immediately following the yield statement.
When a method contains a yield statement, it is expecting to receive a block at calling time. If a block is not provided, an exception will be thrown once the yield statement is reached. We can make the block optional and avoid an exception from being raised:
def meditate
puts "Today we will practice zazen."
yield if block_given?
end meditate
Output:
Today we will practice zazen.
It is not possible to pass multiple blocks to a method. Each method can receive only one block.
See more at: http://www.zenruby.info/2016/04/introduction-to-blocks-in-ruby.html
I sometimes use "yield" like this:
def add_to_http
"http://#{yield}"
end
puts add_to_http { "www.example.com" }
puts add_to_http { "www.victim.com"}
Yields, to put it simply, allow the method you create to take and call blocks. The yield keyword specifically is the spot where the 'stuff' in the block will be performed.
There are two points I want to make about yield here. First, while a lot of answers here talk about different ways to pass a block to a method which uses yield, let's also talk about the control flow. This is especially relevant since you can yield MULTIPLE times to a block. Let's take a look at an example:
class Fruit
attr_accessor :kinds
def initialize
#kinds = %w(orange apple pear banana)
end
def each
puts 'inside each'
3.times { yield (#kinds.tap {|kinds| puts "selecting from #{kinds}"} ).sample }
end
end
f = Fruit.new
f.each do |kind|
puts 'inside block'
end
=> inside each
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
When the each method is invoked, it executes line by line. Now when we get to the 3.times block, this block will be invoked 3 times. Each time it invokes yield. That yield is linked to the block associated with the method that called the each method. It is important to notice that each time yield is invoked, it returns control back to the block of the each method in client code. Once the block is finished executing, it returns back to the 3.times block. And this happens 3 times. So that block in client code is invoked on 3 separate occasions since yield is explicitly called 3 separate times.
My second point is about enum_for and yield. enum_for instantiates the Enumerator class and this Enumerator object also responds to yield.
class Fruit
def initialize
#kinds = %w(orange apple)
end
def kinds
yield #kinds.shift
yield #kinds.shift
end
end
f = Fruit.new
enum = f.to_enum(:kinds)
enum.next
=> "orange"
enum.next
=> "apple"
So notice every time we invoke kinds with the external iterator, it will invoke yield only once. The next time we call it, it will invoke the next yield and so on.
There's an interesting tidbit with regards to enum_for. The documentation online states the following:
enum_for(method = :each, *args) → enum
Creates a new Enumerator which will enumerate by calling method on obj, passing args if any.
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
If you do not specify a symbol as an argument to enum_for, ruby will hook the enumerator to the receiver's each method. Some classes do not have an each method, like the String class.
str = "I like fruit"
enum = str.to_enum
enum.next
=> NoMethodError: undefined method `each' for "I like fruit":String
Thus, in the case of some objects invoked with enum_for, you must be explicit as to what your enumerating method will be.
Yield can be used as nameless block to return a value in the method. Consider the following code:
Def Up(anarg)
yield(anarg)
end
You can create a method "Up" which is assigned one argument. You can now assign this argument to yield which will call and execute an associated block. You can assign the block after the parameter list.
Up("Here is a string"){|x| x.reverse!; puts(x)}
When the Up method calls yield, with an argument, it is passed to the block variable to process the request.

Ruby block parameter error

class MyClass
def test
...
end
end
tmp = MyClass.new
tmp.test do |t|
"here"
end
Why am I getting the error
multiple values for a block parameter (0 for 1)
Here is a slightly longer example, based on your code:
class MyClass
def test
yield self
end
def my_own_puts s
puts s
end
end
tmp = MyClass.new
tmp.test do |t|
t.my_own_puts "here"
end
Running this code will output "here".
What is happening is there is a method test that can take a block of code, so you can call it with the do .. end syntax. Because it is passing an arg to yield, that arg is available to the block, so you give this to the block using the do |some_arg_name| ... end syntax.
The yield is where the block gets executed in the test method, and in this case I to yield I pass in self. Since the block now has access to self (an instance of MyClass), the block can call the my_own_puts method on it, and print out "here".
if test is defined with a yield statement, when that statement is reached and if there is a parameter on the yield statement, that parameter will be put into the block variable t. Thus if you have:
def test
.....
yield x
......
end
then x will be the value of t when yield is executed.
With your help, I was able to get the code working like this
class MyClass
def test
a = yield self
puts a
end
end
tmp = MyClass.new
tmp.test do |t|
"here"
end
Thanks, I had to tweak your code a bit but it works the way I wanted to now.
Passing a block to a function (as Bob shows in his answer) is overkill in this case. If you are reading in a string and printing it out, all you should need is something like:
class MyClass
def test(a)
puts a
end
end
tmp = MyClass.new
tmp.test("here")
Using a block might function correctly, but you are calling a lot of unnecessary code and making the true nature of your code unclear.
Proper block usage aside, let me address the particular error message you are seeing. When you say tmp.test do |t|, Ruby is expecting tmp.test to yield a single value which it will temporarily call t and pass to the block (think like the block is a function and you are passing it the argument your yield statement as a parameter). In your case, the method test method must not be yield-ing anything, thus the message "(0 for 1)" implies that it is seeing zero objects yielded when it is expecting to see one. I don't know what your code for test does, but check and make sure that test yields exactly one value.

Resources