cucumber multiple assertions in a step - cucumber

I am trying to validate one block of json data that I receive from server
json consists of information about bunch of orders. An each order includes cost of each part, taxes and total. And it is kind of strict requirement each order contains exactly 4 parts. And each order has three kind of taxes and a total.
I have a step which looks like this
And "standardorder" includes parts "1..4", taxes "1..3" and total
and step implementation is like following. Here #jsonhelper.json is shared state (json for one order) passed from previous step.
And /^"([^"]*)" includes parts "([^"]*)", taxes "([^"]*)" and total$/ do |arg1, arg2, arg3|
json = #jsonhelper.json
validkeys = ["total"]
parts = arg2.split('..').map{|d| Integer(d)}
(parts[0]..parts[1]).each do |i|
validkeys.push "p#{i}"
end
taxes = arg3.split('..').map{|d| Integer(d)}
(taxes[0]..taxes[1]).each do |i|
validkeys.push "t#{i}"
end
validkeys.each do |key|
json[arg1].keys.include?(key).should be_true
end
end
Now this script works fine except that if any one key is missing it doesn't state which one is missing. Either it passes or fails as assertions are iterated for each key.
I would like to know if there is any possibility of sending keys which are found ok to result stream. Thus my intention is to know to which keys are ok and which failed and which one skipped. As such order of keys is not expected in json.
Thanks in advance.

It's probably best to split the step definitions first:
And "standardorder" should be received
And the order should include parts 1 to 4
And the order should include taxes 1 to 3
And the order should include the total
Then you can re-use the steps elsewhere.
The 'order' check easy to implement as you're just checking one element.
For the other two, you are really just checking the presence of items in an array, e.g.:
actual_values.should == expected_values
If that fails, RSpec will give you a report showing how the arrays differ.

Related

Update a parameter value in Brightway

It seems to be a simple question but I have a hard time to find an answer to it. I already have a project with several parameters (project and database parameters). I would like to obtain the LCA results for several scenarios with my parameters having different values each time. I was thinking of the following simple procedure:
change the parameters' value,
update the exchanges in my project,
calculate the LCA results.
I know that the answer should be in the documentation somewhere, but I have a hard time to understand how I should apply it to my ProjectParameters, DatabaseParameters and ActivityParameters.
Thanks in advance!
EDIT: Thanks to #Nabla, I was able to come up with this:
For ProjectParameter
for pjparam in ProjectParameter.select():
if pjparam.name=='my_param_name':
break
pjparam.amount = 3
pjparam.save()
bw.parameters.recalculate()
For DatabaseParameter
for dbparam in DatabaseParameter.select():
if dbparam.name=='my_param_name':
break
dbparam.amount = 3
dbparam.save()
bw.parameters.recalculate()
For ActivityParameter
for param in ActivityParameter.select():
if param.name=='my_param_name':
break
param.amount = 3
param.save()
param.recalculate_exchanges(param.group)
You could import DatabaseParameter and ActivityParameter iterate until you find the parameter you want to change, update the value, save it and recalculate the exchanges. I think you need to do it in tiers. First you update the project parameters (if any) then the database parameters that may depend on project parameters and then the activity parameters that depend on them.
A simplified case without project parameters:
from bw2data.parameters import ActivityParameter,DatabaseParameter
# find the database parameter to be updated
for dbparam in DatabaseParameter.select():
if (dbparam.database == uncertain_db.name) and (dbparam.name=='foo'):
break
dbparam.amount = 3
dbparam.save()
#there is also this method if foruma depend on something else
#dbparam.recalculate(uncertain_db.name)
# here updating the exchanges of a particular activity (act)
for param in ActivityParameter.select():
if param.group == ":".join(act.key):
param.recalculate_exchanges(param.group)
you may want to update all the activities in the project instead of a single one like in the example. you just need to change the condition when looping through the activity parameters.

In Gatling, how can I generate a random number each time a call is executed? (not using feeder)

I need to find a way to generate a random number each time the REST call is executed.
I have the following GET call:
exec(http("Random execution")
.get("/randomApi")
.queryParam("id", getRandomId()))
}
Obviously it doesn't work as the random number is only generated once and I end up with the same
number whenever this call is executed. I cant use the feeder option as my feeder is already huge and is generated by a 3rd party for each test.
.queryParam takes Expressions as its arguments, and since Expression is an alias for a session function, you can just do...
.queryParam("id", session => getRandomId())
You could also define a second feeder that uses a function to generate the values - no need to update your existing feeder or add another csv file. This would be useful if you had more complicated logic for getting / generating an Id
val idFeeder = Iterator.continually(Map("id" -> Random.nextInt(999999)))
//in your scenario...
.feed(idFeeder)
.exec(http("Random execution")
.get("/randomApi")
.queryParam("id", "${id}")
)
In the spirit of having options, another option you have is to store an object in the session that support toString, which generates whatever you need. It's a nifty trick that you can use for all kinds of things.
object RANDOM_ID {
toString() { return RandomId().toString() }
}
...
exec( _.set( "RANDOM_ID", RANDOM_ID ) )
...
.exec(
http("Random execution")
.get("/randomApi")
.queryParam( "id", "${RANDOM_ID}" )
)
You can apply the same principle to generating random names, addresses, telephone numbers, you name it.
So, which is the better solution? The feeder, or the object in session?
Most of the time, it'll be the feeder, because you control when it is updated. The object in session will be different every time, whereas the feeder solution, you control when the value updates, and then you can reference it multiple times before you change it.
But there may be instances where the stored object solution results in easier to read code, provided you are good with the value changing every time it is accessed. So it's good to know that it is an option.

Cucumber: Step Definitions multiple Optional Group - Capture in same step

I'm trying to write a step that will match the following steps that are similar and capture parameters:
Step1: And I delete the filter(s) using the "UI"
Step2: Then I delete the filter(s) using the "API" for "doc-browser" context
Step3: I delete the filter(s) using the "API" for "doc-browser" context with user "file_user2"
I don't want to create 3 separate steps, they all start with I delete the filter using the #{arg} and the last 2 just extend on that.
I thought this was going to accomplish it:
And(/^I delete the filter\(s\) using the "([^"]*)"(?: for "([^"]*)" context| with user "([^"]*)")?/) do |delete_method, context, user|
case delete_method
when 'API'
if user.nil?
SearchFilters.new.delete_global_local_filters(delete_method, api_context_val: context)
else
SearchFilters.new.delete_global_local_filters(delete_method, { api_context_val: context, username: user })
end
when 'UI'
SearchFilters.new.delete_global_local_filters(delete_method, filter_name: #filter_name)
end
end
However, I'm not capturing my username.
Is it possible to accomplish having one step definition that captures all 3 variations and still captures my arguments?
Just duplicating my mailing list answer in case anyone else is interested in this question.
I understand you don't want to use three different steps, but in this case you really should because
The implementation of each step is a clear one liner, so you are removing a case statement.
The regex for this step is horrible and you will be removing that
Each individual step provides the opportunity to simplify the parameters being passed, you have 2 API and one UI paramter which can just be removed entirely (if I understand the code correctly you can remove all the params and regexs)
This is a clear case where a little bit of repetition is a price well worth paying for a simpler implementation.
Reducing the number of step definitions by using regex's and params is often an anti-pattern.
All best
Andrew

Referencing external doc in CouchDB view

I am scraping an 90K record database using JSON-RPC and I am trying to put in some basic error checking. I want to start by scraping the database twice using two different settings and adding a prefix to the second scrape. This way I can check to ensure that the two settings are not producing different records (due to dropped updates, etc). I wanted to implement the comparison using a view which compares each document from the first scrape with it's twin produced by the second scrape and then emit the names of records with a difference between them.
However, I cannot quite figure out how to pull in another doc in the view, everything I have read only discusses external docs using the emit() function, which is too late to permit me to compare it. In the example below, the lookup() function would grab the referenced document.
Is this just not possible?
function(doc) {
if(doc._id.slice(0,1)!=='$' && doc._id.slice(0,1)!== "_"){
var otherDoc = lookup('$test" + doc._id);
if(otherDoc){
var keys = doc.value.keys();
var same = true;
keys.forEach(function(key) {
if ((key.slice(0,1) !== '_') && (key.slice(0,1) !=='$') && (key!=='expires')) {
if (!Object.equal(otherDoc[key], doc[key])) {
same = false;
}
}
});
if(!same){
emit(doc._id, 1);
}
}
}
}
Context
You are correct that this is not possible in CouchDB. The whole point of the map function is that it must be idempotent, otherwise you lose all the other nice benefits of a pre-calculated index.
This is why you cannot access external resources in the map function, whether they be other records or the clock. Any time you run a map you must always get the same result if you put the same record into it. Since there are no relationships between records in CouchDB, you cannot promise that this is possible.
Solution
However, you can still achieve your end goal, just be different means. Some possibilities...
Assuming there is some meaningful numeric value in each doc, you could use a view to take the sum of all those values and group them by which import you did ({key: <batch id>, value: <meaningful number>}). Then compare the two numbers in your client or the browser to see if they match.
A brute force approach would be to use a view to pair the docs that should match. Each doc is on a different row, but they're grouped by a common field. Then iterate through the entire index comparing the pairs. This would certainly be the quickest to code and doesn't depend on your application or data.
Implement a validation function to enforce a schema on your data. Just be warned that this will reduce your write throughput since each written record will be piped out of Erlang and into the JS engine. Also, this is only applicable if you're worried about properly formed records instead of their precise content, which might not be the case.
Instead of your different batch jobs creating different docs, have them place them into the same doc. The structure might look like this: { "_id": "something meaningful", "batch_one": { ..data.. }, "batch_two": { ..data.. } } Then your validation function could compare them or you could create a view that indexes all the docs that don't match. All depends on where in your pipeline you want to do the error checking and correction.
Personally I like the last option better, but only if you don't plan to use the database as is in production. Ie., you wouldn't want to carry around all that extra data in each record.
Hope that helps.
Cheers.

Determine if a cucumber scenario has pending steps

I would like to retrieve the scenario state in the "After" scenario hook. I noticed that the .failed? method does not consider pending steps as failed steps.
So How can I determine that a scenario did not execute completely, because it failed OR because some steps were not implemented/defined.
You can use status method. The default value of status is :skipped, the failed one is :failed and the passed step is :passed. So you can write something like this:
do sth if step.status != :passed
Also, if you use !step.passed? it does the same thing because it only checks for the :passed status.
http://cukes.info/api/cucumber/ruby/yardoc/Cucumber/Ast/Scenario.html#failed%3F-instance_method
On that subject, you can also take a look at this post about demoing your feature specs to your customers: http://multifaceted.io/2013/demo-feature-tests/
LiohAu, you can use the 'status' method on a scenario itself rather than on individual steps. Try this: In hooks, add
After do |scenario|
p scenario.status
end
This will give the statuses as follows:
Any step not implemented / defined, it'll give you :undefined
Scenario fails (when all steps are defined) :failed
Scenario passes :passed
Using the same hook, it'll give you the status for scenario outline, but for each example row (since for each example row, it is an individual scenario). So if at all you want the result of an entire outline, you'll need to capture result for all example rows and compute the final result accordingly.
Hope this helps.

Resources