I managed to get the test working, though I used a different container adapter. I'll explain the reason for the switch, then how I got the test working.
The danger of embedded containers
In the Arquillian project, we're all about real tests. There's a good reason for this philosophy. If you use mocks or a substitute container when testing code that uses a programming model (i.e., CDI), all you can be sure of is that you've faked out enough functionality to get the test to work. You can't be certain that your code really, truly works.
Obviously, we provide adapters for embedded containers (i.e., substitute containers). The reason is, they often do a decent enough job of simultating the real environment when we are working in development that we are willing to make the trade-off for it's variations. I would expect, though, that you are running the same tests in CI using a real container...just to get that peace of mind.
How do you know when not to use an embedded container?
If you write a test and you are positive it should work, but instead it throws some wacky exception, immediately stop and try the same test in a real container. In your case, I would advise running this test on managed or remote GlassFish, for instance. Both of those adapters use an authentic GlassFish instance. If the test passes, then you have answered the question of this section.
When the embedded container begins to act inconsistently, drop it.
As with all things, there are exceptions to the rule. If the code really *should* work on the embedded container, then it may be worth exploring why it isn't. That may lead you to the discovery of a bug in the library. If debugging the library is your main concern, chase it down. If you are just trying to get a test written for your application code, stop using the embedded container (or save debugging it for a rainy day).
Getting a green bar for this test
The first thing I did was move ValidationService into it's own file. Then you'll see it's clear you need to package it in the ShrinkWrap archive.
package org.arquillian.example;
import javax.validation.constraints.NotNull;
import org.jboss.seam.validation.AutoValidating;
@AutoValidating
public class ValidatedService {
public String method(@NotNull String param) {
return "yes";
}
}
Next, I made some updates to the test. Here's what I changed:
- Add beans.xml to WEB-INF (not META-INF)
- Use try/catch to handle the expected exception (otherwise you get serialization problems w/ the exception class)
- Moved beans-validation.xml to the src/test/resources root
- Disabled the configureFrom() (you don't have to change this...I just put the repositories in my pom.xml to simplify things)
package org.arquillian.example;
import javax.inject.Inject;
import org.hibernate.validator.method.MethodConstraintViolationException;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.resolver.api.DependencyResolvers;
import org.jboss.shrinkwrap.resolver.api.maven.MavenDependencyResolver;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(Arquillian.class)
public class ValidationIT {
@Deployment
public static Archive<?> createTestArchive() {
MavenDependencyResolver resolver = DependencyResolvers.use(MavenDependencyResolver.class)
.loadMetadataFromPom("pom.xml");
WebArchive archive = ShrinkWrap.create(WebArchive.class, "test.war")
.addClasses(ValidatedService.class, ValidationIT.class)
.addAsLibraries(resolver.artifacts("org.jboss.seam.validation:seam-validation-api").resolveAsFiles())
.addAsLibraries(resolver.artifacts("org.jboss.seam.validation:seam-validation").resolveAsFiles())
.addAsWebInfResource("beans-validation.xml", "beans.xml");
return archive;
}
@Inject
private ValidatedService validatedService;
@Test
public void testValidatedService() {
try {
validatedService.method(null);
Assert.fail();
}
catch (MethodConstraintViolationException e) {
// expected
}
}
}
Next, I added a profile for the GlassFish remote container adapter in my pom.xml.
<profile>
<id>arquillian-glassfish-remote</id>
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>1.0.0.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-glassfish-remote-3.1</artifactId>
<version>1.0.0.CR3</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
I then enabled the arquillian-glassfish-remote profile in Eclipse.
Next, I downloaded GlassFish 3.1.2 and extracted it. I setup the container in Eclipse so I could start it from there. Of course you could just start it from the commandline...but then debugging is more difficult.
With GlassFish running and the arquillian-glassfish-remote profile enabled:
Run As > JUnit Test
Green bar
Closing thoughts
Code that uses Solder works fine on GlassFish 3.1.2, but it does not play very nicely with Embedded GlassFish. It's just a hostile environment for CDI because of visibility issues that come with starting an embedded container inside an existing Java process. You end up in a minefield of class visibility and access problems.
If you want the container to start automatically just like embedded, then switch to the arquillian-glassfish-managed-3.1 container. It works almost exactly the same as the remote container, except that Arquillian will start the standalone process at the beginning of the test execution and stop it at the end. In other words,
managed >>>> embedded
But for speed of development:
remote > managed
since you don't have to wait for the container to start...and you can start it in debug mode very easily and keep it there.
Keep that in mind.