I'm trying to test simple class in my Ruby 2.5.0 app:
source/parsers/jira_parser.rb
module Parsers
class JiraParser
def initialize(event)
payload = event['body']
#event = JSON.parse(payload)
end
def call
{
reporter_email: reporter_email,
reporter_name: reporter_name,
ticket_number: ticket_number,
description: description
}
end
private
attr_reader :event
def reporter_email
event.dig('issue', 'fields', 'reporter', 'emailAddress')
end
# other methods from call are pretty much the same as `reporter_email`
With below specs:
spec/source/parsers/jira_parser_spec.rb
require 'spec_helper'
RSpec.describe Parsers::JiraParser do
describe 'call' do
subject(:hash_creation) { described_class.new(event).call }
let(:reporter_name) { 'john.doe' }
let(:reporter_email) { 'john.doe#example.com' }
let(:description) { 'This is a test description' }
let(:event) do
{
'body' => {
'issue': {
'key': 'TEST-Board-123',
'fields': {
'reporter': {
'displayName': reporter_name,
'emailAddress': reporter_email
},
'description': description
}
}
}
}
end
it { expect(hash_creation).to be_success }
end
end
But I've got an error:
NameError:
uninitialized constant Parsers
./spec/source/parsers/jira_parser_spec.rb:5:in `'
No examples found.
Should I add something to my rspec_helper to make it works?
Right now it's pretty basic:
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
end
I understand this is just Ruby, no Rails, hence there's no magic involved. You need to make a source file available in spec file, so you have to put on the top something like:
require_relative '../../../source/parsers/jira_parser
Hello I am still pretty new so this might help but I believe that you need to require JiraParser
require 'jira_parser'
require 'jira_parser/parser'
This might work but the error is because you are trying to use a parser that is not accessible in your current code.
Ok I figured out - all I had to do was to add -I source inside the .rspec file to will load all tested classes. So in my case .rspec will look like below:
.rspec
--require spec_helper
-I source
Related
I've got pure Ruby class which does the parsing of the JSON file to the expected hash (located in src/parsers/incoming_events/create_quiz.rb). I want to test this class with Minitest like below:
# test/src/parsers/incoming_events/create_quiz_test.rb
require 'minitest/autorun'
require_relative '../../../../src/parsers/incoming_events/create_quiz'
module Parsers
module IncomingEvents
class CreateQuiz < ActiveSupport::TestCase
test 'parse JSON to expected format' do
assert_equal expected_hash, service.call
end
private
def service
#service ||= ::Parsers::IncomingEvents::CreateQuiz.new(payload: payload)
end
def payload
{
'quiz' =>
{
'first_name' => 'john',
'last_name' => 'doe',
'ssn' => '1234',
}
}.to_json
end
def expected_hash
{ 'name': 'john doe' }
end
end
end
end
When I'm trying to run above code via ruby test/src/parsers/incoming_events/create_quiz_test.rb I'm getting below error:
test/src/parsers/incoming_events/create_quiz_test.rb:11:in `<module:IncomingEvents>': uninitialized constant Parsers::IncomingEvents::ActiveSupport (NameError)
from test/src/parsers/incoming_events/create_quiz_test.rb:10:in `<module:Parsers>'
from test/src/parsers/incoming_events/create_quiz_test.rb:9:in `<main>'
i want to test an update action in my rails project. The function is running well, but when i try to unit-test it's always fail. Can you help this?
i'm new with ruby and unit-testing. i've tried with any documentation it still not solve this test.
this is my Content Controller function that i want to test, i use clearance for auth
before_action :require_login
def update
#content = Content.find(params[:id])
if #content.update(content_params)
flash[:notice] = 'success'
redirect_back fallback_location: root_path
else
flash[:notice] = 'fail'
redirect_back fallback_location: root_path
end
end
this is my Content Fixture
one:
id: '1'
about: 'about content'
privacy: 'privacy content'
terms: 'terms content'
this is my test_helper
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
require 'clearance/test_unit'
class ActiveSupport::TestCase
fixtures :all
end
class ActionDispatch::IntegrationTest
def sign_in_as_user
user = User.create!(email: "example#example.com", password: "letmein")
post session_url, params: {
session: {
email: user.email,
password: user.password
}
}
end
end
And this is my test code
test "should update content" do
sign_in_as_user
content = contents(:one)
put content_url(content), params: { about: { syarat: "updated about", privacy: "updated privacy", terms: "updated terms" } }
content.reload
assert_equal "updated about", content.about
assert_equal "updated privacy", content.privacy
assert_equal "updated terms", content.terms
end
Then i run the test rake test, this is the result
Failure:
ContentControllerTest#test_should_update_content [/Users/abc/Documents/PROJECT/Apps/test-app/test/controllers/content_controller_test.rb:20]:
--- expected
+++ actual
## -1 +1 ##
-"updated about"
+"about content"
Is there a way to use map and the (lotus)router namespacing together? Below is a sample config.ru I'm trying to get running as a demo.
require 'bundler'
Bundler.require
module Demo
class Application
def initialize
#app = Rack::Builder.new do
map '/this_works' do
run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["this_works"]]}
end
map '/api' do
run Lotus::Router.new do
get '/api/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.params'].inspect }!"]] }
end
end
end
end
def call(env)
#app.call(env)
end
end
end
run Demo::Application.new
Your problem is due to the precedence of do..end in method calls. In your code the section
run Lotus::Router.new do
get '/api/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.params'].inspect }!"]] }
end
is parsed by Ruby as
run(Lotus::Router.new) do
get '/api/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.params'].inspect }!"]] }
end
In other words the block is passed to run, not to Lotus::Router.new as you intended, and run simply ignores the block.
To fix it you need to ensure the block is associated with the constructor of the router rather than the call to run. There are a couple of ways to do this. You could use {...} rather than do...end, as that has a higher precedence:
run Lotus::Router.new {
#...
}
An alternative would be to assign the router to a local variable, and use that as the argument to run:
router = Lotus::Router.new do
#...
end
run router
Sorry for the title, I'm too frustrated to come up with anything better right now.
I have a class, Judge, which has a method #stats. This stats method is supposed to send a GET request to an api and get some data as response. I'm trying to test this and stub the stats method so that I don't perform an actual request. This is what my test looks like:
describe Judge do
describe '.stats' do
context 'when success' do
subject { Judge.stats }
it 'returns stats' do
allow(Faraday).to receive(:get).and_return('some data')
expect(subject.status).to eq 200
expect(subject).to be_success
end
end
end
end
This is the class I'm testing:
class Judge
def self.stats
Faraday.get "some-domain-dot-com/stats"
end
end
This currently gives me the error: Faraday does not implement: get
So How do you stub this with faraday? I have seen methods like:
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('http://stats-api.com') { [200, {}, 'Lorem ipsum'] }
end
But I can't seem to apply it the right way. What am I missing here?
Note that Faraday.new returns an instance of Faraday::Connection, not Faraday. So you can try using
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return("some data")
Note that I don't know if returning "some data" as shown in your question is correct, because Faraday::Connection.get should return a response object, which would include the body and status code instead of a string. You might try something like this:
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(
double("response", status: 200, body: "some data")
)
Here's a rails console that shows the class you get back from Faraday.new
$ rails c
Loading development environment (Rails 4.1.5)
2.1.2 :001 > fara = Faraday.new
=> #<Faraday::Connection:0x0000010abcdd28 #parallel_manager=nil, #headers={"User-Agent"=>"Faraday v0.9.1"}, #params={}, #options=#<Faraday::RequestOptions (empty)>, #ssl=#<Faraday::SSLOptions (empty)>, #default_parallel_manager=nil, #builder=#<Faraday::RackBuilder:0x0000010abcd990 #handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]>, #url_prefix=#<URI::HTTP:0x0000010abcd378 URL:http:/>, #proxy=nil>
2.1.2 :002 > fara.class
=> Faraday::Connection
Coming to this late, but incase anyone else is too, this is what worked for me - a combination of the approaches above:
let(:json_data) { File.read Rails.root.join("..", "fixtures", "ror", "501100000267.json") }
before do
allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(
double(Faraday::Response, status: 200, body: json_data, success?: true)
)
end
Faraday the class has no get method, only the instance does. Since you are using this in a class method what you can do is something like this:
class Judge
def self.stats
connection.get "some-domain-dot-com/stats"
end
def self.connection=(val)
#connection = val
end
def self.connection
#connection ||= Faraday.new(some stuff to build up connection)
end
end
Then in your test you can just set up a double:
let(:connection) { double :connection, get: nil }
before do
allow(connection).to receive(:get).with("some-domain-dot-com/stats").and_return('some data')
Judge.connection = connection
end
I ran into the same problem with Faraday::Adapter::Test::Stubs erroring with Faraday does not implement: get. It seems you need to set stubs to a Faraday adapter, like so:
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get("some-domain-dot-com/stats") { |env| [200, {}, 'egg'] }
end
test = Faraday.new do |builder|
builder.adapter :test, stubs
end
allow(Faraday).to receive(:new).and_return(test)
expect(Judge.stats.body).to eq "egg"
expect(Judge.stats.status).to eq 200
A better way to do this, rather than using allow_any_instance_of, is to set the default connection for Faraday, so that Faraday.get will use the connection you setup in your tests.
For example:
let(:stubs) { Faraday::Adapter::Test::Stubs.new }
let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
before do
stubs.get('/maps/api/place/details/json') do |_env|
[
200,
{ 'Content-Type': 'application/json' },
{ 'result' => { 'photos' => [] } }.to_json
]
end
Faraday.default_connection = conn
end
after do
Faraday.default_connection = nil
end
I am working on a library that needs to be able to download plugin files from a remote API using RestClient. The library first grabs a list of plugins, and then downloads each plugin as a raw file, saving each inside a plugins directory.
Here is what I have thus far but it is failing me:
require 'yaml'
module Monitaur
class Client
attr_accessor :logger, :client_key, :server_url, :config, :raw_config,
:plugin_manifest
def initialize
load_config
#plugin_manifest ||= []
end
def run
get_plugin_manifest
sync_plugins
end
def get_plugin_manifest
res = RestClient.get("#{server_url}/nodes/#{client_key}/plugins")
#plugin_manifest = JSON.parse(res)
end
def sync_plugins
#plugin_manifest.each do |plugin|
res = RestClient.get("#{server_url}/plugins/#{plugin['name']}")
File.open(File.join(Monitaur.plugin_dir, "#{plugin['name']}.rb"), "w+") do |file|
file.write res.body
end
end
end
def load_config
if File.exist?(Monitaur.config_file_path) && File.readable?(Monitaur.config_file_path)
#raw_config = YAML.load_file(Monitaur.config_file_path)
else
raise IOError, "Cannot open or read #{Monitaur.config_file_path}"
end
#server_url = raw_config['server_url']
#client_key = raw_config['client_key']
end
end
end
And the client_spec.rb
require 'spec_helper'
module Monitaur
describe Client do
let(:server_url) { "http://api.monitaurapp.com" }
let(:client_key) { "asdf1234" }
describe "#load_config" do
let(:client) { Monitaur::Client.new }
before do
File.open(Monitaur.config_file_path, "w") do |file|
file.puts "server_url: http://api.monitaurapp.com"
file.puts "client_key: asdf1234"
end
end
it "loads up the configuration file" do
client.load_config
client.server_url.should == "http://api.monitaurapp.com"
client.client_key.should == "asdf1234"
end
end
describe "#get_plugin_manifest" do
let(:client) { Monitaur::Client.new }
before do
stub_get_plugin_manifest
end
it "retrieves a plugins manifest from the server" do
client.get_plugin_manifest
client.plugin_manifest.should == plugin_manifest_response
end
end
describe "#sync_plugins" do
let(:client) { Monitaur::Client.new }
let(:foo_plugin) { mock('foo_plugin') }
let(:bar_plugin) { mock('bar_plugin') }
before do
FileUtils.mkdir("/tmp")
File.open("/tmp/foo_plugin.rb", "w+") do |file|
file.write %|
class FooPlugin < Monitaur::Plugin
name "foo_plugin"
desc "A test plugin to determine whether plugin sync works"
def run
{ :foo => 'foo' }
end
end
|
end
File.open("/tmp/bar_plugin.rb", "w+") do |file|
file.write %|
class BarPlugin < Monitaur::Plugin
name "bar_plugin"
desc "A test plugin to determine whether plugin sync works"
def run
{ :bar => 'bar' }
end
end
|
end
Monitaur.install
stub_get_plugin_manifest
stub_sync_plugins
client.get_plugin_manifest
end
it "downloads plugins to the cache directory" do
File.should_receive(:open).
with(File.join(Monitaur.plugin_dir, "foo_plugin.rb"), "w+")
and_yield(foo_plugin)
client.sync_plugins
File.exist?("/home/user/.monitaur/cache/plugins/foo_plugin.rb").should be_true
File.exist?("/home/user/.monitaur/cache/plugins/bar_plugin.rb").should be_true
end
end
end
end
def stub_get_plugin_manifest
stub_request(:get, "#{server_url}/nodes/#{client_key}/plugins").
to_return(
:status => 200,
:body => %Q{
[
{
"name": "foo_plugin",
"checksum": "qwer5678"
},
{
"name": "bar_plugin",
"checksum": "hjkl4321"
}
]
}
)
end
def plugin_manifest_response
[
{
"name" => "foo_plugin",
"checksum" => "qwer5678"
},
{
"name" => "bar_plugin",
"checksum" => "hjkl4321"
}
]
end
def stub_sync_plugins
stub_request(:get, "#{server_url}/plugins/foo_plugin").
to_return(:body => File.open('/tmp/foo_plugin.rb').read)
stub_request(:get, "#{server_url}/plugins/bar_plugin").
to_return(:body => File.open('/tmp/bar_plugin.rb').read)
end
How can I test the download process?
I use FakeWeb for this purpose, as there's really no need for your spec to fail if the other site is down or something. See "Replaying a recorded response" in the docs. What we do is curl the page, save it somewhere as a fixture and replay that in the specs.