basic undefined method for #<RSpec::ExampleGroups:::0x00000101906440> - ruby

I started and to code back in 2013 and took a break from it and decided to start from scratch. But for the life of me cannot get pass this error. I've done everything I can think of, but it's not requiring the methods from the lib file.
here is my folder structure
fizzbuzz
lib/
fizzbuzz.rb
spec/
fizzbuzz_spec.rb
spec_helper.rb
.rspec
fizzbuzz_spec.rb file
require "fizzbuzz"
describe "fizzbuzz" do
it "tells me that 3 is divisible by 3" do
expect(divisible_by_three?(3)).to_eq true
end
end
Heres the fizzbuzz.rb file
def fizzbuzz
def divisible_by_three? (number)
number % 3 ==0
end
end
Yes I understand it's not the most puzzling thing in the world. But my mind s a blank and I've troubledshoot this and searched online and followed tutorials to do it another way, but it never seems to call the method.
I've used
require "fizzbuzz"
require './lib/fizzbuzz'
require_relative '../lib/fizzbuzz'
Please help, please and thank yous.
Kind regards,
Grateful developer.

There are 2 problems here as I see it. In the lib/fizzbuzz.rb file, your method divisible_by_three? method is enclosed in another method. While this is technically allowed, it's not really advisable if it can be avoided. Instead, change def fizzbuzz to class Fizzbuzz.
class Fizzbuzz
def divisible_by_three? (number)
number % 3 ==0
end
end
In the spec file, require_relative '../lib/fizzbuzz' is fine. However, to use the method (at least as defined in the previous snippet), you'll need to use an instance of the class to have access to the method. See the snippet below.
require_relative '../lib/fizzbuzz'
describe "fizzbuzz" do
let(:instance) { Fizzbuzz.new }
it "tells me that 3 is divisible by 3" do
expect(instance.divisible_by_three?(3)).to eq true
end
end

Related

First time unit testing with rspec in ruby

I am just trying to understand the basics behind unit testing. I wrote a Player class in a file called Player.rb. Here is the code:
Class Player
attr_reader :health
attr_accessor :name
def initialize(name, health=100)
#name = name.capitalize
#health = health
end
def blam
#health -= 10
puts "#{#name} just got blammed yo."
end
def w00t
#health += 15
puts "#{#name} just got w00ted."
end
def score
#health + #name.length
end
def name=(new_name)
#name = new_name.capitalize
end
def to_s
puts "I'm #{#name} with a health of #{#health} and a score of #{score}"
end
end
Here is my spec file:
require_relative 'Player'
describe Player do
it "has a capitalized name" do
player = Player.new("larry", 150)
player.name.should == "Larry"
end
end
Does that seem about right? My question is in regards to the syntax of the spec file. I understand why I need to require the Player class. But what is the describe and it sections of the code doing? Why do I need the it section? All it seems to be doing is defining a string right?
Finally, when I run rspec player_spec.rb from Terminal, I get this warning:
Deprecation Warnings:
Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` instead. Called from /Users/Jwan/studio_game/player_spec.rb:7:in `block (2 levels) in <top (required)>'.
What does the above warning mean? Do I have to replace should with enable syntax? How do I enable the :should syntax? Why is :should written as a symbol?
Yes, that seems about right. One thing you might find useful is to use subject, which lets you define a "subject" to use in multiple tests:
describe Player do
subject { Player.new("larry", 150) }
it "has a capitalized name" do
expect(subject.name).to eq "Larry"
end
end
This way you don't have to define player over and over again in every test—subject will automatically initialize it for you each time.
describe and it are primarily for organization. A large project will ultimately have thousands of tests, and a change in one class might cause a test to fail for a completely different part of application. Keeping tests organized makes it much easier to find and fix errors as they occur.
As for your warning, it looks like you're using an old guide or tutorial that tells you to use "should" syntax, but in RSpec 3 this syntax is deprecated and "expect" syntax is required instead. You can see how I changed your code above to use "expect" syntax. Here's a good blog post on the new syntax (and why the old syntax is deprecated).
it sets up an actual example. An example can be thought of as an actual test which contains one or more expectations (best practice says one expectation per example).
The expect method and matchers only exist in the it block. Variables set up with let and subject are unique for each example.
scenario is an alias for it used in feature (acceptance) specs.
describe, context and feature are used to group examples together. This provides both readability and encapsulation for let and subject variables.
Passing a class to describe also sets up an implicit subject:
RSpec.describe Array do
describe "when first created" do
it { is_expected.to be_empty }
end
end
RSpec has relativly recently undergone a large shift towards eliminating "monkey patching" core ruby classes which depreciated the should syntax.
While it is recommended to use expect for new projects, you can allow should and other monkey patching methods.

Get list of classes and methods that call a specific global method

I have a method called $muffinize and I would like to find where it can be found in my code. In other words, given the following code:
class A
def foo
$muffinize(1)
end
def bar
...
end
end
class B
def shoop
$muffinize(2)
end
def woop
...
end
end
class C
def nope
...
end
end
I would like to the result to be (written to a file):
A:foo
B:shoop
I was thinking of accomplishing this with a Regex, but I was wondering if there would be some way of accomplishing this with Ruby meta-programming (which I might be accidentally using as a buzz-word)?
Kernel.caller() will help you show the line number and method that is calling it at runtime. If you put something like puts caller(1,1) in your muffinize function it will output those locations, but only if they are called at runtime.
If you want to do offline source analysis, you need to parse the AST (abstract syntax tree) with something like https://github.com/whitequark/parser.
Here is a quick example with ripper (built into new rubies) - this isn't strictly an AST but it's not extracting classes either
#!/usr/local/env ruby
require 'ripper'
#require 'pry'
contents = File.open('example.rb').read
code = Ripper.lex(contents)
code.each do |line|
if(line[1] == :on_ident and line[2] == "muffinize")
puts "muffinize found at line #{line.first.first}"
end
end
Ignoring the fact that your code isn't even syntactically valid, this is simply not possible.
Here's a simple example:
class A
def foo
bar
muffinize(1)
end
end
A#foo will call Object#muffinize if and only if bar terminates. Which means that figuring out whether or not A#foo calls Object#muffinize requires to solve the Halting Problem.
By getting a list of classes and methods via ri, I was then able to analyze each method to retreive their source code using the method_source gem and then searching for muffinize. This does not rule out the possibility of muffinize from appearing in a comment or a string, but I consider the likelihood of this happening to be small enough to ignore.

Iterator.each: why is this working

I was refactoring a bit of code in a project for work when I came across an odd bit of syntax. I confirmed it has been in the file since it was first created and the bit of code is being called.
worksheet.each 1 do |row|
Dashboard::LocalizedMessagingField.create({blah blah blah})
end
When I run something like the following in irb it complains about 1 for 0 parameters on each.
[1,2,3].each 1 do |i|
puts i
end
Why does it work in the RoR application? Anyone ever see something like this before?
I found the answer after a bit of digging. We have the Spreadsheet gem installed and it provides an each method that takes a parameter to skip the first n rows of a spreadsheet.
def each skip=dimensions[0], &block
skip.upto(dimensions[1] - 1) do |idx|
block.call row(idx)
end
end

Ruby - Running an iteration by calling require 'filename'

I had a thought and so far the thought has failed so I wanted to share it and have it corrected.
I have a series of Ruby scripts written to walk through a ecommerce site from adding to cart to checking out. The scripts are all referencing each other in order to keep the chain moving along. What I want to do is make a Ruby file called Run_CheckOut.rb but be able to run through several iterations of the checkout by invoking this file x amount of times.
Here was my first try:
i = 0
10.times do
i+= 1
puts "Iteration number: " + i.to_s
require 'Test_OrderService_SubmitCart'
end
When I do this it will only call the required file once but continues to count for i. How can I call the required file 10 times or am I completely off base with this?
am I completely off base with this?
Yes.
What I want to do is make a Ruby file called Run_CheckOut.rb but be able to run through several iterations of the checkout by invoking this file x amount of times.
The point of require is to make code available to your execution environment. require only pulls in the code once -- calling it again has no effect. load will run the included script each time, but that is a poor design choice.
What you want is to invoke something in the source code file. Perhaps you'd like to call a method, or create an object from a class. Define a method:
def do_something
# blah blah
end
require the file at the top of your script:
require 'Test_OrderService_SubmitCart'
and invoke the method in the loop:
i = 0
10.times do
i+= 1
puts "Iteration number: " + i.to_s
do_something
end
You are looking for load (note that you need to append .rb):
load 'Test_OrderService_SubmitCart.rb'
Contrary to load, require executes a source file only once. See the detailed description of what require does in the reference documentation.
Also there is a ruby convention for naming files and methods - lowercased and underscored.
Class and Module names are camel cased. These two conventions are never mixed.
Your final code should look something more like:
require 'order_service'
10.times do |n|
puts "iteration #{n}"
submit_cart
end
Notice the beauty.
Good luck!

Generating many almost identical ruby unit tests

I have a number of ruby files (a.rb, b.rb, c.rb) which define very similar classes. (They should test the same)
I've written a unit test to test these subclasses and I've generated contexts for each of the classes programatically (see below) — should I instead programatically create entire Test Classes instead? If so why and how?
I'm using the shoulda unit test extensions so my files look something like this:
a.rb
class ItsA
def number
1123
end
end
b.rb
class ItsB
def number
6784
end
end
test_letters.rb
require 'rubygems'
require 'test/unit'
require 'shoulda'
class LettersTest < Test::Unit::TestCase
Dir.glob('letters/*.rb') do |letter|
context "The #{letter} letter file"
setup do
# Here I require the ruby file and allocate
# #theclass to be an instance of the class in the file.
# I'm actually testing JavaScript using Harmony, but
# putting those details in might complicate my question.
end
should "return a number" do
assert #theclass.number.is_a? Number
end
end
end
This does the job reasonably well, but should I do some other jiggerypokery and create LetterATest, LetterBTest etc. automatically instead? If so, how would you go about doing it and why?
This really depends on how similar your classes are, but assuming they're pretty much identical and require a few small tests, and you're using shoulda, you could do something like:
class LettersTest < Test::Unit::TestCase
context "The letter classes"
setup do
#instances = # your code to get a list of the instances
end
should "return a number" do
#instances.each do |instance|
assert instance.number.is_a?(Number), "#{instance.class}.number should be a number"
end
end
end
end
In our codebase we've found that a large number of auto-generated contexts and tests leads to pretty slow test execution, so we favor the approach above to minimize the number of contexts/tests. You may not have this issue.

Resources