7 Replies Latest reply: Apr 24, 2012 5:33 AM by Aslak Knutsen RSS

Arquillian @BeforeXxxxx behavior

Chris Williams Newbie

Can someone explain the expected behavior of @BeforeTest and @BeforeClass? We're migrating to Arquillian and having some issues. We're running against a remote server:

 

  1. Methods annotated with @BeforeClass seem to be running before every test. We were using this to setup data before all tests in the class - we would only want this setup to happen once per class, not before each test. We can work around this by using a static variable to control whether or not to run and force only the first execution to run. Is this the expected behavior?
  2. It looks like my methods that have the @BeforeClass annotation are running both inside and outside the container. Should this be happening?
  3. When my @BeforeClass method runs and I try to do a Component.getInstance, I get a "No application context active" error. From my very basic understanding so far of Arquillian, this sounds like it's because the test enrichment hasn't happened. Is there another way to enable me to do this type of thing before my tests run? Is there a way to force the enrichment to happen??
  • 1. Re: Arquillian @BeforeXxxxx behavior
    Craig Ringer Newbie

    My understanding is that the only things in a @RunWith(Arquillian.class) test that should run outside the container are:

     

    - The test class static and instance initializer blocks and variable initializers, if any

    - The test class ctor and any superclass ctors

    - The @Deployment method and anything it calls

     

    No @Test methods should run outside the container, and my understanding is that neither should @Before or @BeforeClass. If they seem to be running outside the container, it'd be a good idea to put together a minimal self-contained test case and submit a bug report. Make sure you're testing against Arquillian 1.0.0.Final (or a newer snapshot).

     

    (3) Probably stems from things running outside the container that shouldn't.

  • 2. Re: Arquillian @BeforeXxxxx behavior
    Chris Williams Newbie

    For #3, it does appear that @BeforeClass and @Before are both running inside the container but Component.getInstance still fails. I assume there's some Seam initialization done before test execution that isn't happening for @BeforeClass annotated methods. I'm looking for some way to do that initialization myself if that's possible.

     

    I'm verifying that we're inside the container using the code below:

     

    private boolean runningInContainer()
        {
            try
            {
                new InitialContext(  ).lookup( "java:comp/env" );
                return true;
            }
            catch (NamingException ex)
            {
                return false;
            }
        }
    

     

  • 3. Re: Arquillian @BeforeXxxxx behavior
    Aslak Knutsen Master

    The current rules for JUnit are:

     

    * BeforeClass / AfterClass are ALWAYS and ONLY executed on the Client side.

    ** Class level state is not keept alive InContainer between @Test, so BeforeClass/AfterClass == Before/After. When doing in container testing the whole test framework lifecycle will be reexecuted pr @Test on the client.

     

    * Before / After are executed depending on the @Test's RunMode, executed on Client side if @Test run on client.

     

    Note: TestNG does currently not give us the option to 'cancel' @BeforeXX|@AfterXX calls, so here they will be executed both on client and incontainer.

  • 4. Re: Arquillian @BeforeXxxxx behavior
    Chris Williams Newbie

    We're using TestNG and we're seeing basically what you indicated - @BeforeClass executing both in the container and the client and also running once per test. Our problem is that we've got hundreds of TestNG tests that we're converting to use Arquillian and JBoss AS 7 that currently use the @BeforeClass annotation to setup test data in the database (used by all @Tests in the class). We need some mechanism to do this with Arquillian where Component.getInstance() will work. For now, our really hacky solution is to override the run() method on Arquillian and do this:

     

     

        private static AtomicBoolean hasSetupComponentsRun = new AtomicBoolean( false );
    
        @Override
        public void run(final IHookCallBack callback, final ITestResult testResult)
        {
            // ugh!
            if ( runningInContainer() && hasSetupComponentsRun.compareAndSet( false, true ))
            {
                setupComponents();
            }
    
            super.run( callback, testResult );
        }
    

     

  • 5. Re: Arquillian @BeforeXxxxx behavior
    Aslak Knutsen Master

    one 'option' would be to move to something like the persistence extension, https://github.com/arquillian/arquillian-extension-persistence that knows a bit more about when it needs to run..

     

    of course that doesn't help you in the case of having your current test suite just work..

     

    Or you could replace @BeforeClass with your own annotation, e.g. @Setup and add a little Arquillian extension that handle that annotation specifically..

  • 6. Re: Arquillian @BeforeXxxxx behavior
    Craig Ringer Newbie

    Thanks for the clarification. I didn't realise @BeforeClass and @AfterClass ran outside the container. That's quite handy, actually, when combined with @Before and @After currently taking over their roles in-container.

     

    OTOH, @BeforeClass and @AfterClass exist to allow expensive setup to be done only once, and it sounds like there's no way to do that at the moment. Given that, is it a good idea to get people used to using them for outside-container work when you may want to support them being run in-container if/when Arq is able to support running multiple @Test methods in one go?

  • 7. Re: Arquillian @BeforeXxxxx behavior
    Aslak Knutsen Master

    Craig, yea matching client and incontainer lifecycles has been proposed: https://issues.jboss.org/browse/ARQ-350

     

    Another open issue is support for controlling where a Before/After run and specially in a mix runmode / multi contianer setup it starts to get a bit hairy.. https://issues.jboss.org/browse/ARQ-351

    A API write up from a while back: http://pastebin.com/WeVnJwzA

     

    Arquillian is some what tied to what the Test Framework we integrate with allow, and we're starting to strech the limits. Implementing some these feature might take us over the fine line of integration vs hacking.