Mocking 2.0, Runtime bytecode manipulation in Integration tests.
@BMRule
and @BMRules
can be placed on both Class and Method level in the TestClass.
The given rules will be active during BeforeClass
or Before
to AfterClass
or After
.
@RunWith(Arquillian.class)
@BMRules(
@BMRule(
name = "Throw exception on success", targetClass = "StatelessManagerBean", targetMethod = "forcedClassLevelFailure",
action = "throw new java.lang.RuntimeException()")
)
public class BytemanFaultInjectionTestCase {
@Deployment
public static Archive<?> createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addClasses(StatelessManager.class, StatelessManagerBean.class);
}
@EJB(mappedName = "java:module/StatelessManagerBean")
private StatelessManager bean;
@Test(expected = EJBException.class)
@BMRule(
name = "Throw exception on success", targetClass = "StatelessManagerBean", targetMethod = "forcedMethodLevelFailure",
action = "throw new java.lang.RuntimeException()")
public void shouldBeAbleToInjectMethodLevelThrowRule()
{
Assert.assertNotNull("Verify bean was injected", bean);
bean.forcedMethodLevelFailure();
}
}
<version.byteman>LATEST_RELEASE</version.byteman>
<dependency>
<groupId>org.jboss.byteman</groupId>
<artifactId>byteman</artifactId>
<version>${version.byteman}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.byteman</groupId>
<artifactId>byteman-submit</artifactId>
<version>${version.byteman}</version>
<scope>provided</scope>
</dependency>
<extension qualifier="byteman">
<property name="autoInstallAgent">true</property>
<property name="agentProperties">org.jboss.byteman.verbose=true</property>
</extension>
-
autoInstallAgent
(default false) Iftrue
the extension will attempt to install the Byteman Agent in the target Container runtime. Iffalse
it assumes the Byteman Agent is manually installed.autoInstallAgent
requirestools.jar
on the container classpath to perform the installation. -
agentProperties
Additional properties to use when auto installing the Byteman Agent. See the Byteman documentation for more details.
As we are using Arquillian Chameleon, it's very easy to run the tests against different containers. To see the comprehensive list of what is supported out-of-the-box check here.
To run test against different version of WildFly only change chameleonTarget
like follow:
$ mvn test -Darq.container.chameleon.configuration.chameleonTarget="wildfly:10.1.0.Final:managed"
If you have not provided chameleonTarget
then it will take default value provided in your arquillian.xml
.
While running the tests from an IDE, variable ${path.tools_jar}
in arquillian.xml
is not defined, as it's only defined in Maven build. Thus the execution results with NoClassDefFoundError
. One possible way to overcome this problem is to hardcode Byteman settings in arquillian.xml
pointing to the tools.jar
file from your JDK. See commented out section in arquillian.xml
.
To run the tests against the remote container make sure that you started your server with following VM arguments:
-Djboss.modules.system.pkgs=com.sun.tools.attach,org.jboss.byteman -Xbootclasspath/a:${path.tools_jar}
If you want to do this from Eclipse IDE, go to "Edit Launch Configuration" of your server, append above parameter in VM arguments before you start.
When using autoInstallAgent
with application server such as WildFly, a number of JDK version-dependent parameters need to be passed to the JVM:
For JDK 8 and below: the com.sun.tools.attach
and org.jboss.byteman
packages have to be exposed as system packages and tools.jar
added to the bootstrap classpath.
<property name="javaVmArguments">-Djboss.modules.system.pkgs=com.sun.tools.attach,org.jboss.byteman -Xbootclasspath/a:${path.tools_jar}</property>
For JDK 9 and above: the com.sun.tools.attach
and org.jboss.byteman
packages have to be exposed as a system packages and -Djdk.attach.allowAttachSelf=true
passed as a system property.
<property name="javaVmArguments">-Djboss.modules.system.pkgs=org.jboss.byteman -Djdk.attach.allowAttachSelf=true</property>