Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to validate ScenarioState in order to generate indicative exception message and/or stack trace #473

Open
adrian-herscu opened this issue Jun 23, 2020 · 4 comments

Comments

@adrian-herscu
Copy link

Consider having a Given stage with a ProvidedState field:

class Given extends Stage<Given> {
        @ScenarioState
        private final ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
        Given init(final WebDriver webDriver) {
            this.webDriver.set(webDriver);
            return self();
        }
}

Now in a scenario:

public void shouldDoSomething() {
    // forgotten to call: given().init(someWebDriver);
    when()...
    then()...
}

Running the above will generate a NullPointerException with a stack trace like:

java.lang.NullPointerException
	at com.tngtech.jgiven.impl.ScenarioModelBuilder.setStatus(ScenarioModelBuilder.java:244)
	at com.tngtech.jgiven.impl.ScenarioModelBuilder.scenarioFailed(ScenarioModelBuilder.java:316)
	at com.tngtech.jgiven.impl.ScenarioExecutor.failed(ScenarioExecutor.java:470)
	at com.tngtech.jgiven.testng.ScenarioTestListener.onTestFailure(ScenarioTestListener.java:94)
	at org.testng.internal.TestListenerHelper.runTestListeners(TestListenerHelper.java:67)
	at org.testng.internal.Invoker.runTestListeners(Invoker.java:1389)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:636)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
	at org.testng.TestRunner.privateRun(TestRunner.java:648)
	at org.testng.TestRunner.run(TestRunner.java:505)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
	at org.testng.SuiteRunner.run(SuiteRunner.java:364)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
	at org.testng.TestNG.runSuites(TestNG.java:1049)
	at org.testng.TestNG.run(TestNG.java:1017)
	at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
	at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:110)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:64)

which does not indicate what the real problem is.

Is there some way to validate ScenarioState's and generate some custom message?

One way would be to add to each step method the following requiresNonNull(webDriver, "you forgot to call given")...

Is there someway to make it happen during the stage initialization?

@l-1squared
Copy link
Collaborator

Hi @adrian-herscu,
while I like the idea of having descriptive error messages, this seems to be something that requires a rather large amount of work. I'd need to take a deep look into the code first to figure out what would need to be done here.

@adrian-herscu
Copy link
Author

Hi @adrian-herscu,
while I like the idea of having descriptive error messages, this seems to be something that requires a rather large amount of work. I'd need to take a deep look into the code first to figure out what would need to be done here.

How the injection happens? Which injection mechanism is used? May there is some feature in the dependency injection framework to help with this?

@l-1squared
Copy link
Collaborator

l-1squared commented Jun 25, 2020

Hi,
I tried to understand and answer your question. The injection of fields should happen in ValueInjector. There are additional injection places for @ScenarioState. Hence the injection is mostly self-written with a little help of ByteBuddy to help with proxying stages.

I need to mention however that I failed miserably at the reproduction of your example. Which is very unfortunate, because I wanted to use that to get a grasp of where one might actually could hook in to prevent the error you described.

Maybe @janschaefer can provide a little more insight, on where such a hook would need to be placed.

@adrian-herscu
Copy link
Author

I need to mention however that I failed miserably at the reproduction of your example. Which is very unfortunate, because I wanted to use that to get a grasp of where one might actually could hook in to prevent the error you described.

Can I help with that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants