I work on an app with Sinatra framework. I would know where the best place is to store a mapping method: in a controller or a decorator. In fact, I import data from a French website that has a French territory, and I want to convert the number territory from number to name.
Here is my method:
def territory_mapping(code)
{
'01' => 'Auvergne-Rhône-Alpes',
'02' => 'Hauts-de-France',
'03' => 'Auvergne-Rhône-Alpes'
}[code]
end
I want to know where I can store this method.
begin
case "my hash's use" do
when "it's for display" then
if "it's a small method"
"put it in a helper for use a controller"
else
"put it in a module and include it using via `helper`"
end
when "it's not for display" then "put it in a helper for use in a route block"
else
"it should go in the class that requires it."
end
rescue NoMethodError => e
e.message = <<~MESSAGE
If it doesn't work because the logic isn't defined
in your views or route blocks then it should go in
the class that requires it."
MESSAGE
ensure
"I get out more so I stop answering this question in Ruby ;-)"
end
In other words, put it in a helper and then you can assess later whether it should go somewhere else.
Regardless, #tadman is right about declaring that example hash as a constant, you should treat access to that as you would to any other constant - if you need it in more than one place then have it the level above in the namespace hierarchy. If it's a lot of data then #Stefan is right to say to load it from somewhere else.
Related
Hi I want to know how can I write rspec for the following
def find_user(content)
user = User.find(content.to_i) ||
User.find(email: content) rescue
nil
end
I tried writing
It "user with user name" do
expect(User).to receive(:find).with(email: "test#a.com").and_return(user)
End
But I am gettig error saying
Argument Error
Block not Passed
Can someone please tell what am i missing
I may look first at your code here.
def find_user(content)
user = User.find(content.to_i) ||
User.find(email: content) rescue
nil
end
What is content? I looks like you're expecting either a user_id or an email address.
Doing this from the console:
irb(main):080:0> User.find("email#email.com".to_i)
=> ActiveRecord::RecordNotFound (Couldn't find User with 'id'=0)
So it seems as if having a generic find_user method may be contributing to some of the test writing confusion.
Many times, overly complex tests point to overly complex code.
Perhaps you need one method
find_user_by_email(email)
and another
find_user_by_id(id)
Also, refer to https://api.rubyonrails.org/v6.1.3.2/classes/ActiveRecord/FinderMethods.html#method-i-find_by
It will automatically return nil if nothing is found.
Start there, And then like the other commenters, then post your class, and the spec and we can go from there.
I'd like to access Delayed::Worker instance to call say on it to save some messages in delayed_log file. Is there any simple way to achieve such behaviour?
class SomeDelayedJob
def perform
worker = __?__ # Delayed::Worker instance which called that perform method
worker.say('going to do x')
do_x()
end
end
Your best bet would be to use
Delayed::Worker.logger.[info|error|warn|debug] "going to do x"
with some formatting :)
because say internally uses the same logger object
Edit
Delayed::Worker.logger.[info|error|warn|debug] "#{Process.pid} at #{Time.now} => going to do x"
Hope this help
I have a page object called LineItemsPage
class LineItemsPage
attr_accessor :add_line_item_button
def initialize(test_env)
#browser = test_env[:browser]
#action_bar = #browser.div(:id => 'lineitems_win').div(:class => 'window-body').div(:class => 'actionbar')
#add_line_item_button = #action_bar.img(:class => 'button add')
end
def method_missing(sym, *args, &block)
#browser.send sym, *args, &block
end
end
I use it like so:
When /^I click on Add Item and enter the following values:$/ do |table|
#line_items_page = LineItemsPage.new(#test_env)
#line_items_page.add_line_item_button.when_present.click
end
I'm wondering if I should be abstracting the click, by adding something like the following to my LineItemsPage class:
def add_item
self.add_line_item_button.when_present.click
end
And then using it like so:
#line_items_page.add_item
I'm looking for best practices, either with regards to Page Object in particular or Ruby in general. I feel that encapsulating the interface by using add_item() is going a bit far, but I'm wondering if I'm unaware of issues I might run into down the road if I don't do that.
Personally, I try to make my page object methods be in the domain language with no reference to the implementation.
I used to do something like #line_items_page.add_line_item_button.when_present.click, however it has caused problems in the following scenarios:
1) The add line item was changed from a button to a link.
2) The process for adding a line item has changed - say its now done by a right-click or it has become a two step process (like open some dropdown and then click the add line).
In either case, you would have to locate all the places you add line items and update them. If you had all the logic in the add_item page object method, you would only have to update the one place.
From an implementation perspective, I have found that Cheezy's page object accessors work pretty well. However, for image buttons (or any of your app's custom controls), I would add additional methods to the PageObject::Accessors module. Or if they are one off controls, you can add the methods directly to the specific page object.
Update - Reply to Comment Regarding Some Starting Points:
I have not come across too much documentation, but here are a couple links that might help:
1) The Cheezy Page Object project wiki - Gives a simple example to get started
2) Cheezy's blog posts where the page object gem first started. Note that the content here might not be exactly how the gem is currently implemented, but I think it gives a good foundation to understanding what he is trying to achieve. This in turn makes it easier to understand what is happening when you have to open up and modify the gem to fit you needs.
I'd like to know about idioms or best practices for testing a multi-step workflow using rspec.
Let's take as an example a "shopping cart" system, where the buying process might be
when user submits to basket and we are not using https, redirect to https
when user submits to basket and we are using https and there is no cookie, create and display a new basket and send back a cookie
when user submits to basket and we are using https and there is a valid cookie and the new item is for a different product than the first item, add a line to the basket and display both lines
when user submits to basket and we are using https and there is a valid cookie and the new item is for the same product as a previous one, increment that basket line's quantity and display both lines
when user clicks 'checkout' on the basket page and is using https and there is a cookie and the basket is non-empty and ...
...
I've read http://eggsonbread.com/2010/03/28/my-rspec-best-practices-and-tips/ which advises i.a that each "it block" should contain only one assertion: instead of doing the computation and then testing several attributes in the same block, use a "before" inside a context to create (or retrieve) the object under test and assign it to #some_instance_variable, then write each attribute test as a separate block. That helps a little, but in a case such as outlined above where testing step n requires doing all the setup for steps [1..n-1] I find myself either duplicating setup code (obviously not good) or creating lots of helper functions with increasingly unwieldy names (def create_basket_with_three_lines_and_two_products) and calling them consecutively in each step's before block.
Any tips on how to do this less verbosely/tediously? I appreciate the general principle behind the idea that each example should not depend on state left behind by previous examples, but when you're testing a multi-step process and things can go wrong at any step, setting up the context for each step is inevitably going to require rerunning all the setup for the previous n steps, so ...
Here's one possible approach -- define an object that creates the necessary state for each step and pass it forward for each successive one. Basically you need to mock/stub the method calls for all the setup conditions:
class MultiStep
def initialize(context)
#context = context
end
def init_vars
#cut = #context.instance_variable_get(:#cut)
end
def setup(step)
init_vars
method(step).call
end
def step1
#cut.stub(:foo).and_return("bar")
end
def step2
step1
#cut.stub(:foo_bar).and_return("baz_baz")
end
end
class Cut # Class Under Test
def foo
"foo"
end
def foo_bar
"foo_bar"
end
end
describe "multiple steps" do
before(:each) do
#multi_stepper = MultiStep.new(self)
#cut = Cut.new
end
it "should setup step1" do
#multi_stepper.setup(:step1)
#cut.foo.should == "bar"
#cut.foo_bar.should == "foo_bar"
end
it "should setup step2" do
#multi_stepper.setup(:step2)
#cut.foo.should == "bar"
#cut.foo_bar.should == "baz_baz"
end
end
Certainly too late for OP, but this could be handy for others - the rspec-steps gem seems to be built for this exact situation: https://github.com/LRDesign/rspec-steps
It might be worthwhile to look at https://github.com/railsware/rspec-example_steps and https://github.com/jimweirich/rspec-given as well. I settled on rspec-steps, but I was in a rush and these other options might actually be better for all I know.
I'm implementing a service that has several different ways it can be accessed:
Using simple query parameters
With parameters encoded as a Javascript object
For some calls both GET and POST are supported, with POST being used when there is large amounts of data being sent to the service.
What's the best way to structure my RSpec tests to avoid unnecessarily repeating code, allowing me to run the same basic assertions each time?
I'm already using shared_examples to capture some comment tests for things like response code, mimetype, etc. But I'm wondering whether there are other options, particularly when I want to invoke the service using all request methods AND a range of expected inputs and outputs.
The way I would do it in this case is to specify the request as a lambda that performs it. That way I can refer to it in my shared specs and set a different one for each type of request.
I like using rspec describe blocks when its sets an expectation, in this case that a particular request method is used. The whole thing will look something like this:
describe FooController do
shared_examples_for "any request" do
it "assigns foo" do
#request.call
assigns[:foo].should == "bar"
end
it "does not change the number of bars" do
#request.should_not change(Bar, :count)
end
end
context "using GET" do
before do
#request = lambda { get "index" }
end
it_should_behave_like "any request"
end
end
An even cleaner way is to use the 'let' construct, although it may be a step too deep in rSpec magic for a novice:
describe FooController do
shared_examples_for "any request" do
it "assigns foo" do
request.call
assigns[:foo].should == "bar"
end
it "does not change the number of bars" do
request.should_not change(Bar, :count)
end
end
context "using GET" do
let(:request) { lambda { get "index" } }
it_should_behave_like "any request"
end
end