Scenario
I'm writing a library (no Ruby on Rails) for which I'd like to have very detailed Cucumber features. This especially includes describing errors/exceptions that should be thrown in various cases.
Example
The most intuitive way to write the Cucumber steps would probably be something like
When I do something unwanted
Then an "ArgumentError" should be thrown
Problem
There are two issues I have to address:
The first step should not fail when an exception is thrown.
The exception that the first step throws should be accessible to the second step in order to do some assertion magic.
Unelegant And Cumbersome Solution
The best approach I've been able to come up with is caching the exception in the first step and putting it into an instance variable that the second step can access, like so:
When /^I do something unwanted$/ do
begin
throw_an_exception!
rescue => #error
end
end
Then /^an "(.*)" should be thrown$/ do |error|
#error.class.to_s.should == error
end
However, this makes the first step more or less useless in cases where I don't want it to fail, and it requires an instance variable, which is never a good thing.
So, can anyone help me out with an at least less cumbersome solution? Or should I write my features differently anyway? Any help would be much appreciated.
I thought about it once more, and maybe the answer is:
There is no elegant solution, because the Given-When-Then-Scheme is violated in your case.
You expect that "Then an exception should be thrown" is the outcome of "When I do something unwanted".
But when you think about it, this is not true! The exception is not the outcome of this action, in fact the exception just shows that the "When"-Statement failed.
My solution to this would be to test at a higher level:
When I do something unwanted
Then an error should be logged
or
When I do something unwanted
Then the user should get an error message
or
When I do something unwanted
Then the program should be locked in state "error"
or a combination of these.
Then you would "cache the exception" in your program - which makes perfect sense, as you most likely need to do that anyway.
The two problems you've stated would be solved, too.
In case you really must test for exceptions
Well, i guess then cucumber isn't the right test suite, hmm? ;-)
As the Given-When-Then-Scheme is violated anyway, I would simply write
When I do something unwanted it should fail with "ArgumentError"
and in the step definitions something like (untested, please correct me if you try it)
When /^I do something unwanted it should fail with "(.*)"$/ do |errorstring|
expect {
throw_an_exception!
}.to raise_error(errorstring)
end
As said above, that is horribly wrong as the scheme is broken, but it would serve the purpose, wouldn't it? ;-)
You'll find further documentation at testing errors at rspec expectations.
One option is to mark the scenario with #allow-rescue and check the page's output and status code. For example
In my_steps.rb
Then(/^the page (?:should have|has) content (.+)$/) do |content|
expect(page).to have_content(content)
end
Then(/^the page should have status code (\d+)$/) do |status_code|
expect(page.status_code.to_s).to eq(status_code)
end
Then /^I should see an error$/ do
expect(400..599).to include(page.status_code)
end
In my_feature.feature
#allow-rescue
Scenario: Make sure user can't do XYZ
Given some prerequisite
When I do something unwanted
Then the page should have content Routing Error
And the page should have status code 404
or alternatively:
#allow-rescue
Scenario: Make sure user can't do XYZ
Given some prerequisite
When I do something unwanted
Then I should see an error
This may not be exactly what you were hoping for, but it might be an acceptable workaround for some people who come across this page. I think it will depend on the type of exception, since if the exception is not rescued at any level then the scenario will still fail. I have used this approach mostly for routing errors so far, which has worked fine.
It is possible to raise an exception in a When block and then make assertions about it in the following Then blocks.
Using your example:
When /^I do something unwanted$/ do
#result = -> { throw_an_exception! }
end
Then /^an "(.*)" should be thrown$/ do |error|
expect{ #result.call }.to raise_error(error)
end
That example uses RSpec's matchers but the important part is the -> (Lambda); which allows the reference to the throw_an_exception! method to be passed around.
I hope that helps!
I'm answering from the perspective of someone who uses Cucumber features in a Behavior-Driven Development situation, so take it or leave it...
Scenarios should be written to test a 'feature' or functionality of the application, as opposed to being used to test the code itself. An example being:
When the service is invoked
Then a success code should be returned
It sounds like your test case (i.e. If I do this, then this exception should be thrown) is a candidate for unit or integration testing - in my case, we would use some Mocking or unit testing framework.
My suggestion would be to re-evaluate your feature scenarios to see if they are really testing what you intend them to test. From personal experience, I've found that if my test classes are becoming abnormally complex, then my features are 'wrong.'
Related
I am a bit mitigated concerning the use of Guard Clauses in Ruby.
The style that is suggested by Rubocop is to use the "do if condition_fails"
Often I want to generate useful error messages with the guard clause, which results in long lines if I want to keep use the aforementionned style, and the "if" will often be pushed off the screen (I don't like line wrapping).
The problem is that as a developer, I don't really care about the error message but rather the code condition itself (which is sometimes more explicit than the error message).
Example of a Guard Clause which hides visibility for the dev
def crtical_function(params)
fail Exception.new("Useful message for the user, but not often useful message for the dev, and as you can see this line is veeeeeeerrrrrry long and just annoying because the dev is rather looking for the condition itself which is often more einteresting than an error message") if not_enough_params
end
Without the Guard clause style, you understand right away
def crtical_function(params)
if not_enough_params
fail Exception.new("Useful message for the user, but not often useful message for the dev, and as you can see this line is veeeeeeerrrrrry long and just annoying because the dev is rather looking for the condition itself which is often more einteresting than an error message")
end
end
So hum yeah the story is that I just installed rubycop and it started highlighting a lot of things including those if condition fail end code blocks suggesting to transform them to Guard clauses. I wasn't sure how to react to these.
Is there a setting to configure or maybe a workaround to preserve developer visibility while getting rid of complaints of not writing a guard clause ? What are your suggestions to compromise visibility/guidelines compliance ?
This is very subjective. First of all, in both cases you are breaking another de-facto convention that wants a line of code to not exceed 80 chars.
All these conventions are inheritance from the days when monitors were reasonably small, hence having long lines was uncomfortable and could possibly hide important statements as you noticed.
Personally, I use the one-line style only when performing pre-validation, in general at the beginning of the method or when I have several short conditions in sequence.
Regardless the style you use, you may also want to consider extracting the message in a variable so that the final code is more readable.
def critical_function(params)
message = "Useful message for the user, but not often useful message for the dev, and as you can see this line is veeeeeeerrrrrry long and just annoying because the dev is rather looking for the condition itself which is often more einteresting than an error message"
fail Exception.new(message) if not_enough_params
end
def critical_function(params)
message = "Useful message for the user, but not often useful message for the dev, and as you can see this line is veeeeeeerrrrrry long and just annoying because the dev is rather looking for the condition itself which is often more einteresting than an error message"
if not_enough_params
fail Exception.new(message)
end
end
Extracting the message also allows you to store it in a constant and/or freeze it, and/or perform other interpreter optimizations.
Furthermore, you can also consider to wrap the string.
Finally, speaking of conventions, I'd be more worried about following the naming conventions for the methods, rather than forcing to one style for the if-statement.
Ruby methods are underscore_case, not camelCase:
critical_function
and not
criticalFunction
So I'm kind of new to Protractor. I've written a number of parameterised functions (eg loginAs, navigateTo, enterTextIntoSearchField, clickButton etc), which I can then use repeatedly as I create my specs and suites. So for example I might have a "perform search" suite, with specs for "perform search as regular user", "perform search as admin" etc.
All this is fine. I'm using the Jasmine2HTMLReporter which produces output similar to sample Jasmine2HTMLReporter output
Some of my reusable functions have expect statements, some don't (although I may yet go back and try to add them for clarity!)
The problem I have is when an individual spec consists of quite a few function calls, the list of passed / failed expectations in the report can be rather long. In the case of failed expectations it gives details of the failure ("expected Fred to equal Bob" etc). However, I would like to see something similar for the passes aswell ("expected Fred to equal Fred") - as this would allow whoever was reading the report to understand which function call any one "passed" related to - and understand the flow of the test, rather than just seeing an otherwise meaningless list of "Passed" statements.
Is this at all possible? I could have nested specs so that each function call was it's own spec within a "parent" spec, but this strikes me as over the top and messy, and would make the report way bigger than it needed to be? Would a different reporter give me what I want? I've not found one yet that looks like it would...
So, here's the deal. I'm currently working in a Ruby on Rails environment and have been for ~1 year now. Before that I was in C++/Java land for almost a decade. I'm (still) trying to figure out what the Ruby way is when it comes to asserts.
I'm not worried about the technical detail. I know TestUnit has asserts which can be used in the testing environment and I know I can add my own assert methods to my Ruby project and use them in production Rails to lock down known conditions. The question is: What is the Ruby way for ensuring something in code that I know should/not happen?
For the record, I've been asserting in tests and raising in production. I still can't help but miss my production asserts...
Asserts really shouldn't be used in production code for two reasons.
assert x is very functional, and as such hard to read. Using a raise/if combo adds readability.
assert doesn't make it clear what error will be raised if the condition fails. While,
raise ObscureButInformitiveError if condition
lets the application layers further up do something relveant. Such as emailing an admin, or writing to a perticular log.
Let the error happen, then check the logs for what went wrong, then fix it.
Rails catches all uncaught exceptions automatically, it will only mess up the single request the error happened in.
There's no official non-test assertions in Ruby, but there are gems.
For instance Jim Weirich's Given looks promising. Although its main focus is testing environments (rspec / minitest), but it also:
... provides three assertions meant to be used in
non-test/non-spec code. For example, here is a square root function
decked out with pre and post-condition assertions.
require 'given/assertions'
require 'given/fuzzy_number'
include Given::Assertions
include Given::Fuzzy
def sqrt(n)
Precondition { n >= 0 }
result = Math.sqrt(n)
Postcondition { result ** 2 == about(n) }
result
end
To use the
non-testing assertions, you need to require the 'given/assertions'
file and then include the Given::Assertions module into what ever
class is using the Precondition / Postcondition / Assert methods. The code
block for these assertions should always be a regular Ruby true/false
value (the should and expect methods from RSpec are not available).
Note that this example also uses the fuzzy number matching, but that
is not required for the assertions themselves.
This is somewhat of a broad question, but it is one that I continue to come across when programming in Ruby. I am from a largely C and Java background, where when I use a library function or method, I look at the documentation and see what it returns on error (usually in C) or which exceptions it can throw (in Java).
In Ruby, the situation seems completely different. Just now I need to parse some JSON I receive from a server:
data = JSON.parse(response)
Naturally, the first thing I think after writing this code is, what if the input is bad? Is parse going to return nil on error, or raise some exception, and if so, which ones?
I check the documentation (http://flori.github.com/json/doc/JSON.html#M000022) and see, simply:
"Parse the JSON string source into a Ruby data structure and return it."
This is just an example of a pattern I have run into repeatedly in Ruby. Originally, I figured it was some shortcoming of the documentation of whatever library I was working with, but now I am starting to feel this is standard practice and I am in a somewhat different mindset than Ruby programmers. Is there some convention I am unaware of?
How do developers deal with this?
(And yes I did look at the code of the library method, and can get some idea of what exceptions are raised but I cannot be 100% sure and if it is not documented I feel uncomfortable relying on it.)
EDIT: After looking at the first two answers, let me continue the JSON parsing example from above.
I suspect I should not do:
begin
data = JSON.parse(response)
raise "parse error" if data.nil?
rescue Exception => e
# blahblah
end
because I can look at the code/tests and see it seems to raise a ParserError on error (returning nil seems to not be standard practice in Ruby). Would I be correct in saying the recommended practice is to do:
begin
data = JSON.parse(response)
rescue JSON::ParserError => e
# blahblah
end
...based upon what I learned about ParserError by looking through the code and tests?
(I also edited the example to clarify it is a response from a server that I am parsing.)
(And yes I did look at the code of the library method, and can get some idea of what exceptions are raised but I cannot be 100% sure and if it is not documented I feel uncomfortable relying on it.)
I suggest having a look at the tests, as they will show some of the "likely" scenarios and what might be raised. Don't forget that good tests are documentation, too.
Should you want to discard non valid JSON data:
begin
res = JSON.parse(string)
rescue JSON::ParserError => e
# string was not valid
end
I guess that if no documentation is provided, you have to rely on something like this :
begin
# code goes here
rescue
# fail reason is in $!
end
You can never be sure what exceptions can be raised, unless the library code catches all and then wraps them. Your best bet is to assume good input from your code by sanitising what goes in and then use your own higher level exception handling to catch bad input from your inputs.
Your question boils down to basically two questions: is there a convention or standard for finding possible exceptions, and also where is the documentation related to such a convention?
For the first question, the closest thing to a convention or standard is the location and existence of an exceptions.rb file. For libraries or gems where the source code is publicly available, you can typically find the types of exceptions in this file. (Ref here).
If source code is not available or easily accessed, the documentation is your next best source of information. This brings us to your second question. Unfortunately documentation does not have a consistent format concerning potential exceptions, even in standard libraries. For example, the Net::Http documentation doesn't make it obvious what exceptions are available, although if you dig through it you will find that all exceptions inherit from Net::HTTPExceptions.
As another example (again from the standard library documentation), JSON documentation shows an Exception class (which is indeed in an exceptions.rb file, albeit in the source at json/lib/json/add/exceptions.rb). The point here is that it's inconsistent; the documentation for the Exception class is not listed in a way similar to that of Net::HTTPException.
Moreover, in documentation for most methods there is no indication of the exception that may be raised. Ref for example parse, one of the most-used methods of the JSON module already mentioned: exceptions aren't mentioned at all.
The lack of standard and consistency is also found in core modules. Documentation for Math doesn't contain any reference to an exceptions.rb file. Same with File, and its parent IO.
And so on, and so on.
A web search will turn up lots of information on how to rescue exceptions, and even multiple types of exceptions (ref here, here, here, here, etc). However, none of these indicate an answer to your questions of what is the standard for finding exceptions that can be raised, and where is the documentation for this.
As a final note, it has been suggested here that if all else fails you can rescue StandardError. This is a less-than-ideal practice in many cases (ref this SO answer), although I'm assuming you already understand this based on your familiarity with Java and the way you've asked this question. And of course coming from a Java world, you'll need to remember to rescue StandardError and not Exception.
I really don't see a sane use for these. There is already rescue and raise, so why the need for throw and catch? It seems they are supposed to be used to jump out of deep nesting, but that just smells like a goto to me. Are there any examples of good, clean use for these?
Note: It looks like a few things have changed with catch/throw in 1.9. This answer applies to Ruby 1.9.
A big difference is that you can throw anything, not just things that are derived from StandardError, unlike raise. Something silly like this is legal, for example:
throw Customer.new
but it's not terribly meaningful. But you can't do:
irb(main):003:0> raise Customer.new
TypeError: exception class/object expected
from (irb):3:in `raise'
from (irb):3
from /usr/local/bin/irb:12:in `<main>'
They can be really useful in simplifying DSLs for end users by passing control out of the DSL without the need for complex case / if statements
I have a Ruby app which allows users to extend it via an internal DSL. Some of the functions in the DSL need to return control to specific parts of my application. Let's take a simple example. Suppose the user is developing a simple extension concerning dates
if today is a holiday then
do nothing
end
week_of_year = today.week.number
if week_of_year < 10 then
...
The do nothing bit triggers a throw which passes control out of the exec statement and back to me.
Rather than continuing to execute the DSL, on some condition, we want it to exit and hand control back to my application. Now you could get the user to use lots of embedded if statements and have the DSL end naturally but that just obscures what the logic is trying to say.
Throw really is a goto which is 'considered dangerous' but damn it sometimes they are the best solution.
It's basically a goto, and slightly more akin to a call/cc, except that the control flow is wired up implicitly by name instead of explicitly as a parameter. The difference between throw/catch and raise/rescue is that the former is intended to be used for control flow instead of only exceptional situations, and it doesn't waste time putting together a stack trace.
Sinatra uses throw/catch for HTTP error codes, where a handler can use throw to cede control to the Sinatra library in a structured way. Other sorts of HTTP frameworks use exceptions, or by returning a different class of response, but this lets Sinatra (for example) try another request handler after catching it.
The difference between the two is that you can only 'raise' exceptions but can 'throw' anything (1.9). Other than that, they should be interchangeable, that is, it should be possible to rewrite one with another, just like the example given by #john-feminella.