Closed adrian-herscu closed 11 months ago
Hi @adrian-herscu
I think this problem is more a limitation of the Java language rather than JGiven (Type erasure).
usually Stage classes are declared as MStage extends Stage<MStage>
now, the generic type is always known and the compiler can infer the return type.
You however told the compile that MStage is MStage<?>
so the return type is an unspecifed capture of which the compiler can make no assumption.
likewise with addStage(NFixtrues.class)
you pass the type-erased class literal for NFixtures<Stage>
i.e. NFixtures<?>
Using them as generic types should not be necessary, if you don't intend to subclass them further. If you need to keep the generics, I suggest you try to cast to a more specific generic type.
Feel free, to close. If I hear nothing from you, I'll close it on Friday
Using them as generic types should not be necessary, if you don't intend to subclass them further. If you need to keep the generics, I suggest you try to cast to a more specific generic type.
I must reuse them somehow... I am developing system tests, and these always require working with multiple interfaces, like Selenium, JDBC, ElasticSearch, RabbitMQ, REST... So my initial tought was to build generic steps for these, hold them in some separate JAR artifacts and then reuse them by subclassing. My current scheme looks like this:
classDiagram
Stage <|-- StageEx
StageEx <|-- GenericFixtures
StageEx <|-- GenericActions
StageEx <|-- GenericVerifications
GenericFixtures <|-- WebDriverFixtures
GenericActions <|-- WebDriverActions
GenericVerifications <|-- WebDriverVerifications
GenericFixtures <|-- RestFixtures
GenericActions <|-- RestActions
GenericVerifications <|-- RestVerifications
GenericFixtures <|-- RabbitMQFixtures
GenericActions <|-- RabbitMQActions
GenericVerifications <|-- RabbitMQVerifications
Further, each application has its specific steps derived from these, adding an additional layer of subclasses for each relevant interface. A scenario may look like this:
given a REST interface XXX
and a JDBC interface YYY
and an ElasticSearch interface ZZZ
when calling some REST method
then calling other REST method returns something
and the DB contains something
and the ElasticSearch query returns something
All my trouble appeared later when I discovered that additional stages do not play well with TestNG's parallel modes. Any other suggestion(s)?
Ok, so I manage to reproduce your issue:
@Test
public void test() {
given().a_thing_doer();
when().do_thing().and().move_result();
then().thing_doer_should_say_hello_world();
addStage(ExtraStage.class).smile().and().wave().and().hope_nobody_saw_that();
// ^we fail here
}
static class ExtraStage<T extends ExtraStage<T>> extends Stage<T> {
@ProvidedScenarioState
private String result;
public T smile(){
return self();
}
public T wave(){
return self();
}
public T hope_nobody_saw_that(){
return self();
}
}
But I am still conviced that this is a java, and not a JGiven limitation... I actually noticed that we kap of the generic chain at Stage
-> Stage<T extends Stage<?>>
but even after replacing that with T
the error persisted.
Thankfully, I could resolve the issue with
((ExtraStage<?>)addStage(ExtraStage.class)).smile().and().wave().and().hope_nobody_saw_that();
I suggest you follow that example, I cannot see a way to fix that issue on my end.
Thankfully, I could resolve the issue with ((ExtraStage<?>)addStage(ExtraStage.class)).smile().and().wave().and().hope_nobody_saw_that(); I suggest you follow that example, I cannot see a way to fix that issue on my end.
Instead of ((ExtraStage<?>)addStage(ExtraStage.class))
we can use:
public ExtraStage<?> extraStage() {
return addStage(NFixtures.class);
}
This is what I did originally.
Then I tried adding @IntroWord
-- but it has no effect.
So instead of just writting extraStage().smile()
, I have to write extraStage().given().smile()
.
Any possible cure for that?
I would have to look deeper into what "has no effect" actually means here, before setting out for a cure
I would have to look deeper into what "has no effect" actually means here, before setting out for a cure
Well... It seems that @IntroWord
has an effect only on Stage
methods -- hence adding it to a Scenario
method has no effect.
Am I wrong? The end-result is that the scenario writer has to explicitly add given()
or other intro word on each invocation of each additional stage.
Let's remember that all this begun with JGiven not supporting injected stages in parallel TestNG modes.