quarkus: QuarkusTransaction not working in Unit-Test since 2.16

Describe the bug

We came across a regression when moving from Quarkus 2.15.3 to 2.16.4 where the static QuarkusTransaction calls fail when running in a unit-test (without a container) giving java.lang.NullPointerException: Cannot invoke "io.quarkus.arc.ArcContainer.instance(java.lang.Class, java.lang.annotation.Annotation[])" because the return value of "io.quarkus.arc.Arc.container()" is null

As stated in the documentation, QuarkusTransaction is supposed to work everywhere, using a no-op when no TX is available. see https://quarkus.io/guides/transaction

Expected behavior

Unit-Test runs to completion

Actual behavior

NullpointerException is thrown

How to Reproduce?

Define Bean with TX-semantics

@Singleton
public class TxBean {
    public void doStuff(){
        // using deprecated version to switch between versions. New api yields the same error
        QuarkusTransaction.run(() -> System.out.println("Hello TX"));
    }
}

Define a unit-test

public class TxBeanTest {

    @Test
    public void test(){
        var sut = new TxBean();
        sut.doStuff();
    }
}

Run it -> fails

Change version back of Quarkus to 2.15.3 Run again -> Success

Output of uname -a or ver

No response

Output of java -version

openjdk version “17.0.6” 2023-01-17

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.16.4

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.1

Additional information

As a workaround falling back to method annotated with @Transactional solves the issue

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 22 (22 by maintainers)

Most upvoted comments

I still think we should have a unit testing story. We’ve been hearing this constantly and don’t have a good answer at the moment. QuarkusUnitTest is great for certain things, but it’s relatively slow compared to “just” booting the CDI container. Something like Weld JUnit, e.g. ArcTestContainer or the ArC Arquillian adapter, would be a good fit for a lot of unit testing cases, I think.

The scope is limited but you never know what other services are used in the dependency tree. Also not all extensions use CDI everywhere.

It’s a unit test, so only direct dependencies matter and they’re supposed to be stubbed or mocked. So yes, you’ll know what other services you need quickly enough through trial and error.

Anyway… The consensus seems to be that the specific behavior requested in this should not be supported, and adding more testing extensions for actual unit tests is not desirable at the moment. So I’ll close this.

Thanks for the input everyone!

I mean CDI dependencies.

Your bean might call a static method in Quarkus (say, QuarkusTransaction.run) that retrieves a CDI bean dynamically (Arc.container().whatever). You care about that dependency, and you’ll easily notice it by running your test and looking at the failure, and then you’ll mock it.

But you don’t care about that dependency’s transitive dependencies, because you mocked it, hopefully removing all transitive CDI dependencies.

I suppose you can also build a little wrapper around QuarkusTransaction and make it default to no-op if Arc.container() returns null. Not great, but may be better than alternatives.

But when putting it behind a mockable wrapper, the question remains why I should use it at all. I could then just also wrap the TransactionManager, though the API is worse (CheckedException, Commit, Rollback etc)…but only in one place which aleviates the pain a bit