How can I control transaction handling in Arquillian using JUnit5?

55 views Asked by At

I have a project, working fine, when I deploy the EAR to Jboss EAP. The behavior is as expected.

I also can test my project with Arquillian with a lot of tests, but I observed now the following behavior (below).

I observed the behavior in combination using Hibernate envers @Audited, that each @Test will be wrapped with a transaction or?

Environment:

  • Java 11
  • Jboss EAP 7.4.7

Dependencies (Gradle):

    api 'org.hibernate:hibernate-core:5.3.28.Final'
    api 'org.hibernate:hibernate-envers:5.3.28.Final'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
    testFixturesApi 'org.jboss.arquillian.protocol:arquillian-protocol-servlet:1.8.0.Final'
    testFixturesApi 'org.wildfly.arquillian:wildfly-arquillian-container-managed:4.0.1.Final'
    testFixturesApi 'org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-gradle-depchain:3.2.1'
    testFixturesApi 'org.jboss.arquillian.junit5:arquillian-junit5-container:1.8.0.Final'
    testFixturesApi 'org.junit.jupiter:junit-jupiter-api:5.10.1'

Entities (stripped):

@Entity
@Audited
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Component implements HasEntityId {
  ...
}

@Entity
@Audited
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Node extends Component {
  ...
}

@Entity
@Audited
@Table(name = "tbl_server")
public class Server extends Node {
  ...
}

Beans (stripped):

@Stateless
public class NodeBeanImpl implements NodeBean {
...
    @Override
    @Transactional
    public Node create(Node node) {   // confusing name, but using entityManager.merge, so not only create also updating
        ....
        return savedNode;
    }
    
    @Override
    public void modifyAndDelete(Node node, String description) {
        node.setDescription(description);
        Node n = create(node);
        System.out.println("DESCR: " + n.getDescription());
        delete(n);
    }

    @Override   // NO TRANSACTION!!!!!
    public Optional<Node> getByHostNameAndDomainName(String hostName, String domainName) {
    return ...
    }
}

I observed the behavior, when I checking the envers audit records! In the following test I see, the @Test method will be wrapped (automatically?)

The example is changing the property "description" for demonstration.

@ExtendWith(CertificateArquillianExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class OTest {
    @Deployment(testable = true)
    public static JavaArchive createDeployment() {
        JavaArchive jar = JUnitHelperEJB.buildEJBWithPublic(false);
        return jar;
    }

    @Inject
    private NodeBean nodeBean;

    private static UUID lastId;

    @Test
    @Order(100)
    void testCreateAndModify() {
        Node node = new Server("1", "1", "descr01", "system01.ula.de", "1.1.1.1");
        node = nodeBean.create(node);
        
        node.setDescription("descr02");
        node = nodeBean.create(node);
        lastId = node.getId();
        // I get TWO (2) audit records with "descr01" and "descr02"
    }

    @Test
    @Order(110)
    void testReadAndModifyTwice() {
        Node node = nodeBean.getByHostNameAndDomainName("system01", "ula.de").get(); //Optional!
        assertThat(node.getId(), is(lastId));
        assertThat(node.getDescription(), is("descr02"));
        node.setDescription("descr03");
        node = nodeBean.create(node);
        node.setDescription("descr04");
        node = nodeBean.create(node);
        assertThat(node.getDescription(), is("descr04"));
        // I get FOUR (4) audit records with "descr01", "descr02", "descr03", "descr04".
    }
    
    @Test
    @Order(120)
    void testDelete() {
        Node node = nodeBean.getByHostNameAndDomainName("system01", "ula.de").get(); //Optional!
        assertThat(node.getId(), is(lastId));
        assertThat(node.getDescription(), is("descr04"));
        nodeBean.modifyAndDelete(node, "descr05");
        // I get FIVE (5) audit records with "descr01", "descr02", "descr03", "descr04" and a "DEL" record,
        // but NO "descr05" !!!
    }
}

So I do NOT find the change with descripton="descr05" as an audit record, I just see until "descr04" and next revision is the delete record. modifyAndDelete is modifying the node, and store with create.

Then I delete, so I just must get two audit records.

I just simplified my test case for Stackoverflow.

When I deploy the same logic to Jboss EAP, I will see my missing audit record, so change to "descr05" is a audit record! I also have seen in another test, calling another method in my bean and than asking entity manager em.isJoinedToTransaction(). I saw, after calling nodeBean.getByHostNameAndDomainName in the @Test, that em.isJoinedToTransaction() changed from false to true. Sound to me, Arquillian is wrapping.

So it looks for my, the call getByHostNameAndDomainName turn on a transaction. The inner create, delete are parts of the @Test transaction, envers will not see this changes until finally committing from the @Test?

So I think, Arquillian is wrapping the transaction handling automatically with in a @Test using a @Stateless bean?

I found a lot of examples with Junit4 and

@Transactional(value = TransactionMode.DISABLED)

It may work? Unfortunately I just change to Junit5 a few weeks ago. I do not want go back.

Can I control the transaction handling in my Junit5 environment?

0

There are 0 answers