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

Use @ArquillianResource instead of @RubyResource to inject test resources #1

Closed
robertpanzer opened this issue Mar 2, 2015 · 7 comments
Assignees

Comments

@robertpanzer
Copy link
Contributor

Currently Ruby and ScriptingContainer instances are injected on the test class or method if an annotation @RubyResource is present, e.g.:

public class MyRubyTest {
    @RubyResource
    private Ruby testClassScopedRuby;

    @Test
    @RubyScript("test.rb")
    public void test(@RubyResource Ruby methodScopedRuby) {...}
}

To align the resource injection with other arquillian resource this should be changed to using @ArquillianResource as well.

@ArquillianResource requires a ResourceProvider to return the resource in ResourceProvider.lookup() .
Until arquillian-core 1.1.7.Final it was not possible to distinguish a field injection from a parameter injection.
Therefore I used the @RubyResource annotation so that the resource is created by a TestEnricher that has access to the concrete method.

Since 1.1.8.Final it is possible to distinguish field from parameter injection so that the way to using @ArquillianResource is open again.
Unfortunately one thing is still missing:

Before the test method is executed scripts defined in the @rubyscript annotation have to be executed on a Ruby instance:

  • If the test method has a Ruby instance injected into a parameter the scripts should be executed in the context of this test scoped Ruby instance
  • Otherwise the script should be executed in the context of the test class scoped Ruby instance.

Following solutions are possible imo:

  1. Access the test method in ResourceProvider.lookup() and fetch the @rubyscript annotation. Unfortunately there is still no way to access the RubyScript annotation in the Resource Provider.
  2. Another approach could be to observe a LocalExecutionEvent after enrichment that executes the scripts, but ArquillianResource test method enrichment and test execution are done in one step in LocalTestExecutor.execute and there is no way to get in between.
  3. A workaround would be to cache the test method in a Before observer and use that information in the ResourceProvider. For execution of scripts without parameter injected Ruby instances that are to be executed on the field injected Ruby instance this would require another event observer.
@aslakknutsen
Copy link
Member

In general @ResourceProviders are intended just as a hook to Inject resources, not as a place to do work.

In your case I guess a @observes EventContext could work. AroundInvoke the Test event. Or possible just in Before as you have no 'After' behavior.

You then have to know about if this is a MethodLevel or not and produce/operate on the correct Ruby script container for later to inject that instance back in the ResourceProvider.

robertpanzer added a commit to robertpanzer/arquillian-container-jruby that referenced this issue Mar 2, 2015
… fields annotated with @ArquillianResource
@robertpanzer
Copy link
Contributor Author

@aslakknutsen Do you think firing a JRubyScriptExecution event from a Before observer or ResourceProvider.lookup() depending on class or method based script execution is a reasonable solution?

@aslakknutsen
Copy link
Member

A bit skeptical about the event fired in ResourceProvider but.. Doesn't sound too bad.

Another approach I guess would be to;

  • create Class level Ruby in BeforeClass scoped to ClassScope
  • create Method level Ruby in Before scoped to TestScope (only produce if method argument injection is available)
  • fire JRubyScriptExecution in Before (later in the phase then the create above)
  • JRubyScriptExecution inject Ruby, and it will get which ever Ruby instance is the 'closest', Method if available or Class if not
  • ResourceProvider this would need some logic to choose which Ruby based on level of injection... (possible add support for Scope on Instance to limit which scope this given instance can come from to Core.. hmm.)

@robertpanzer
Copy link
Contributor Author

OK, I could already create the method level ScriptingContainer here in the Before observer:
https://github.com/robertpanzer/arquillian-container-jruby/blob/2ebdec405b0d9459211b208017a692ce198f69fd/src/main/java/org/arquillian/jruby/embedded/JRubyTestObserver.java#L43

Then the ResourceProvider would get even simpler because it's only returning an instance that is already created. Great idea.
Will change my PR accordingly.

Thank you!

@robertpanzer
Copy link
Contributor Author

@aslakknutsen Only thing I find a bit disturbing about

  • create Class level Ruby in BeforeClass scoped to ClassScope

is that it makes the extension inspect the class for @ArquillianResource ScriptingContainer and Ruby fields if I want to create the instance only on demand.

So I would have to duplicate this code:
https://github.com/arquillian/arquillian-core/blob/master/test%2Fimpl-base%2Fsrc%2Fmain%2Fjava%2Forg%2Fjboss%2Farquillian%2Ftest%2Fimpl%2Fenricher%2Fresource%2FArquillianResourceTestEnricher.java#L51

@aslakknutsen
Copy link
Member

Essentially yeah. Planning a nicer API around that kinda reflection work but..

testClass.getClass().getDeclaredFields().each { it.type == Ruby|SciptContainer && it.isAnnotationPresent(ArquillianResource)}

@robertpanzer
Copy link
Contributor Author

Thank you! Just updated the PR #2. It is so much cleaner now (except for searching ArquillianResource annotations on the fields;-) )
...Still so much to learn for me.

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