Closed mkschulze closed 3 years ago
Hi Mark!
The @step
decorator would be replaced with either @given
, @when
, or @then
. In actuality, they all expand to the same thing, so it doesn't matter which one you use for a step, but for readability I think it's best to separate them. The above steps would look like
using ExecutableSpecifications
@then "connection has been opened" begin
@expect context[:cllient] !== nothing && is_open(context[:client])
end
@then "connection does not have any database" begin
@expect length(get_all(databases(context[:client]))) == 0
end
Note that I'm guessing above about what the actual Grakn methods will look like in Julia, but that's how the steps look like anyway.
Also, be aware that there's a very good chance that this will change very slightly soon. So, above the context
variable is magically in scope, which is because I put it in scope in the macros for @{given,when,then}
. That is subject to change. It will instead probably look something, but not necessarily exactly like this (I'm not even sure the below code is correct)
using ExecutableSpecifications
@then "connection has been opened" context -> begin
@expect context[:cllient] !== nothing && is_open(context[:client])
end
@then "connection does not have any database" context -> begin
@expect length(get_all(databases(context[:client]))) == 0
end
So, instead of just having a begin/end
block, the macro will instead take an anonymous function that will explicitly name context
.
I'll let you know if/when this happens though.
Ok, thank you. That helps!
the @expect macro is from your package and is the same as the @assert macro that can be found in Julia?
@expect
is from my package, yes. It's not exactly the same assert the @Assert
macro, I think. I'm fairly sure I throw a custom exception from @expect
. I need to make sure that @assert
works well, too. It'll work, but if it fails, then the step will be listed as having had an unexpected exception, rather than failing.
ok, I'll use @expect then. Did you do the @expect as a safe way and independent of debugging settings? I read in python the execution of assert() might be disabled, according to the debug settings. Just curious.
I genuinely don't remember exactly why, but that sounds reasonable.
I think I initially looked at using the @test
macro from the Test package, but I couldn't use it directly. I think I just made my own version of that.
Yeah, I think the use of @step
seems to be a bad practice. The testing code looks better with @given
, @when
, and @then
because the intention is more explicit.
Question is answered I think, closing now.
Reopening this to make sure I'm on the right track with the syntax.
from behave import *
from tests.behaviour.context import Context
@step("connection has been opened")
def step_impl(context: Context):
assert context.client and context.client.is_open()
@step("connection does not have any database")
def step_impl(context: Context):
assert len(context.client.databases().all()) == 0
I assume this would now look like
@given("connection has been opened") do context
@fail context[:cllient] !== nothing && is_open(context[:client])
end
@given("connection does not have any database") do context
@fail length(get_all(databases(context[:client]))) == 0
end
is this about right @erikedin?
The assert macro ought to be @expect
instead of @fail
. The fail macro unconditionally fails the step.
The @expect
macro checks the conditions, which is what you want here.
Other than that, it all looks good.
Ok, somehow the suggestmissingsteps function seems to always suggest a @fail statement. Good to know, I'll change it then, thx!
Can I ask another one? That would help me a lot I think.
There is this expression in python:
@step("{var:Var} = attribute({type_label}) as(boolean) put: {value:Bool}")
def step_impl(context: Context, var: str, type_label: str, value: bool):
context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).as_boolean().put(value))
so, the context .put method comes from an internal class here:
public class ThingSteps {
private static Map<String, Thing> things = new HashMap<>();
public static Thing get(String variable) {
return things.get(variable);
}
public static void put(String variable, Thing thing) {
things.put(variable, thing);
}
from here: https://github.com/graknlabs/client-java/blob/master/test/behaviour/concept/thing/ThingSteps.java
What I've done now is this:
@when("{var:Var} = attribute({type_label}) as(boolean) put: {value:Bool}") do context
@expect put(var::String, context[:tx(), :concepts(), :get_attribute_type(type_label::String), :as_remote(context[:tx()]), :as_boolean(), :put(value::bool)])
end
But it could be pretty wrong I fear.
I'm not entirely sure, but I think they're using the put methods to place arbitrary objects in a specific place in the context, to share them between steps. This is something you could use the context for directly. The context is meant to carry objects from one step to another. I'm guessing, but I think they use the put method because Pythons behave doesn't let you set arbitrary fields based on what you get from the step, only hard-coded fields.
I don't know what tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).as_boolean().put(value))
does, but it looks like they use this step to set some attribute on some Grakn transaction. This is something I probably can't help you with much, I'm afraid.
The part that does put on the context
context.put(var, ...)
could easily be converted to Julia with
context[Symbol(var)] = ...
It's how I always intended context to be used. There's probably some reason the Grakn team added a put
method on Behaves Context
but I'm not sure it applies for ExecutableSpecifications, as you can already do this natively.
Also, you don't need the @expect
macro here. The step appears to be used to perform some action and put some objects in the context for the next step to use. It doesn't assert anything, so @expect
isn't needed.
ok, yes it's ment to set the background conditions of the scenarios here:
Feature: Concept Attribute
Background:
Given connection has been opened
Given connection does not have any database
Given connection create database: grakn
Given connection open schema session for database: grakn
Given session opens transaction of type: write
# Write schema for the test scenarios
Given put attribute type: is-alive, with value type: boolean # this is the one
Given put attribute type: age, with value type: long
Given put attribute type: score, with value type: double
Given put attribute type: birth-date, with value type: datetime
Given put attribute type: name, with value type: string
Given put attribute type: email, with value type: string
Given attribute(email) as(string) set regex: \S+@\S+\.\S+
Given put entity type: person
Given entity(person) set owns attribute type: is-alive
Given entity(person) set owns attribute type: age
Given entity(person) set owns attribute type: score
Given entity(person) set owns attribute type: name
Given entity(person) set owns attribute type: email
Given entity(person) set owns attribute type: birth-date
Given transaction commits
Given connection close all sessions
Given connection open data session for database: grakn
Given session opens transaction of type: write
This is how it's done in java
@When("{var} = attribute\\( ?{type_label} ?) as\\( ?boolean ?) put: {bool}")
public void attribute_type_as_boolean_put(String var, String typeLabel, boolean value) {
put(var, tx().concepts().getAttributeType(typeLabel).asBoolean().asRemote(tx()).put(value));
}
Maybe like this then? What do you think @tk3369 ?
@when("{var:Var} = attribute({type_label}) as(boolean) put: {value:Bool}") do context
context[Symbol(var)] = [:tx(), :concepts(), get_attribute_type(:type_label::String), :as_remote(context[:tx()]), :as_boolean(), :put(value::bool)]
end
got it I think, can be closed.
Hi @erikedin,
I'm trying to write the integration tests from here currently, and they all start with a @step decorator in python.
How would you translate this to Julia using your package?