weld / weld-testing

Set of test framework extensions (JUnit 4, JUnit 5, Spock) to enhance the testing of CDI components via Weld. Supports Weld 5.
http://weld.cdi-spec.org/
Apache License 2.0
102 stars 30 forks source link

Provide support for declarative TX and transactional observers #65

Open gunnarmorling opened 5 years ago

gunnarmorling commented 5 years ago

Hey, first of all, thanks a lot for this project, it's very helpful!

One thing I was missing is support for declarative TX control (via @Transactional) and transactional observers. This needs JTA to be hooked up.

I figured out the steps needed and added an example to our demos repo in Hibernate: https://github.com/hibernate/hibernate-demos/pull/39

Also planning to write a blog post about this, but actually it'd be great if this was working out-of-the-box in Weld JUnit. I.e. there could be a new module, "persistence" or so, which does all the things I had to do manually:

WDYT?

gunnarmorling commented 5 years ago

@antoinesd, interested in your opinion as well :)

manovotn commented 5 years ago

I think this would be an interesting yet very specific addition and that it should be an independent feature that you can but don't need to run in your tests. This gets somewhat trickier in combination with the fact that we need a solution for junit4 and junit5 both of which operate differently.

Ideally, we would have this as separate module, but you will need to somehow access the Weld object we create so that you can register you beans (producers) and transactional service with it (some static method allowing that perhaps?).

If you can cobble together a PR, we can go from there.

gunnarmorling commented 5 years ago

Ideally, we would have this as separate module

Yes, that was my very thinking, too. By adding this module, a user would get support for JPA/JTA.

If you can cobble together a PR, we can go from there.

That'd be fantastic!

gunnarmorling commented 5 years ago

Here's my blog post on the topic which also contains an example implementation:

http://in.relation.to/2019/01/23/testing-cdi-beans-and-persistence-layer-under-java-se/

The code is in the hibernate-demos repo and I've rewritten it slightly now, so everything is easily usable via a JUnit rule. I think you could essentially pull over this rule into a new weld-junit-persistence module and this would already be of great help.

webczat commented 5 years ago

to be honest, I am wondering why weld just doesn't provide an supposedly optional feature to have a default TransactionServices implementation that looks up transaction related objects via jndi, for example. There are transaction managers that are used in java se apps, and none of them including narayana has provided it's own implementation of this. That would leave only entity manager factory and such like to be done.

Bukama commented 4 years ago

Were any further actions done here? I'm heavily struggeling with the transaction context, while trying to adopt @gunnarmorling example to my test project (here executing a very simple CDI Test which looks exactly like in @gunnarmorling project but in my it fails )

INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Mรคr 22, 2020 6:20:07 PM org.jboss.weld.event.ExtensionObserverMethodImpl checkRequiredTypeAnnotations
INFO: WELD-000411: Observer method [BackedAnnotatedMethod] org.jboss.weld.junit5.auto.TestInstanceInjectionExtension.rewriteTestClassScope(@Observes ProcessAnnotatedType<T>, BeanManager) receives events for all annotated types. Consider restricting events using @WithAnnotations or a generic type with bounds.

java.lang.NoSuchMethodError: javax.enterprise.inject.spi.ObserverMethod.getPriority()I

I found #80 that this error comes from a older jboss-classfilewriter, but this should be fixed in the weld-unit5 version I use (using currentv2.0.1.Final )

If you want to have a look at my testing project it would be the StringBuilderWeldTest in the EJB module.

manovotn commented 4 years ago

@Bukama your error is different from what's in #80.

ObserverMethod.getPriority() is CDI 2.0 and weld-junit now supports that (and not 1.2). Are you by any chance overriding that to CDI 1.2? Since I would guess that can be the issue.

Bukama commented 4 years ago

@Bukama your error is different from what's in #80.

ObserverMethod.getPriority() is CDI 2.0 and weld-junit now supports that (and not 1.2). Are you by any chance overriding that to CDI 1.2? Since I would guess that can be the issue.

Oh thanks. Sorry if I pollute this thread. In my demo project I'll have JavaEE 7 (so CDI 1.2) application as I'm trying to set up this testing environment for our work situation (yeah Java EE 7 ...). Will try to go back to an older version of weld-junit. If you have any advises feel free to contact me at e.g. twitter (@bukamabish)

manovotn commented 4 years ago

No problem. Just note that weld-junit has swapped to CDI 2.0 and any future releases will be targetting that or newer versions. We don't plan to maintain CDI 1.2 support.

x80486 commented 2 months ago

[...a few years later]

Hi everyone! ๐Ÿ‘‹ ...I came across this thread while trying to integrate a declarative transactional approach in a simple application that uses Weld and Jakarta Persistence.

I wanted to ask if there has been any consideration for introducing support for this in the testing library :thinking:

manovotn commented 2 months ago

[...a few years later]

Hi everyone! ๐Ÿ‘‹ ...I came across this thread while trying to integrate a declarative transactional approach in a simple application that uses Weld and Jakarta Persistence.

I wanted to ask if there has been any consideration for introducing support for this in the testing library ๐Ÿค”

Hello

there has been no work done in this regard and this issue has mostly been buried and forgotten I am afraid :) That being said, if you are willing to work on it and send some draft/PR, we can definitely consider this as some form of an optional module for weld-junit.

x80486 commented 2 months ago

I'm on the other side of the fence for this one because I wouldn't know where to start :sweat_smile:

I'll leave this one up for a more qualified soul.

Thanks foe the update! :raised_hands:

manovotn commented 2 months ago

I'm on the other side of the fence for this one because I wouldn't know where to start ๐Ÿ˜…

I'll leave this one up for a more qualified soul.

Thanks foe the update! ๐Ÿ™Œ

In one of the earlier comments there is a link to a sample code that has some of the internals we'd use.

Then there's a question of how to include this. If it should be:

I'd say it's better to keep it optional but OFC we could start by adding it directly and then taking a look at how much luggage does that amount to.

manovotn commented 2 months ago

Thinking about it some more, we might be able to re-use (or repurpose) org.jboss.weld.junit5.WeldJunitEnricher - if the optional module had that service implementation, it would be picked up :thinking:

manovotn commented 2 months ago

I tried playing with this a little but my knowledge in the JPA area is pretty much nonexistent so that's making it hard to know what kind of wiring do we need/want. It also does bring in a lot of dependencies - hibernate core parts for JPA bits and Narayana core for JTA. Furthermore, a dependency on org.jboss.weld.module:weld-jta would be required (in weld-testing) to properly provision a UserTransaction through an implementation of org.jboss.weld.transaction.spi.TransactionServices.

@x80486 do you have a sample (or more) of tests that you would expect to work? Just to give me a more complete idea of what we'd need to cover.

x80486 commented 2 months ago

x80486 do you have a sample (or more) of tests that you would expect to work? Just to give me a more complete idea of what we'd need to cover.

Thank you for looking into this :1st_place_medal:

I'll create a small repository so you can test this โ€” give me a couple of hours to put everything together. It will be everything working in main, and a weld-jta-test branch with the changes using the annotations instead.

manovotn commented 2 months ago

x80486 do you have a sample (or more) of tests that you would expect to work? Just to give me a more complete idea of what we'd need to cover.

Thank you for looking into this ๐Ÿฅ‡

I'll create a small repository so you can test this โ€” give me a couple of hours to put everything together. It will be everything working in main, and a weld-jta-test branch with the changes using the annotations instead.

Thank you. And no need to rush, I probably won't be able to get back to it until early next week :)

x80486 commented 2 months ago

This is the repository: jakarta-persistence-weld-testing.zip

On main you can run ./gradlew clean check; that will run all test cases successfully.

$ git status 
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
$ ./gradlew clean check 
To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.10.2/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build 
> Task :clean
> Task :processResources
> Task :processTestResources
> Task :generateEffectiveLombokConfig
> Task :compileJava
> Task :classes
> Task :generateTestEffectiveLombokConfig
> Task :compileTestJava
> Task :testClasses
> Task :test
> Task :check

BUILD SUCCESSFUL in 7s
8 actionable tasks: 8 executed

If you change to the branch weld-jta-test and repeat the same process you will see some failures โ€” I think it's because currently the @Transactional annotation has no effect when the Weld container starts and wires up everything.

$ git checkout weld-jta-test 
Switched to branch 'weld-jta-test'
Your branch is up to date with 'origin/weld-jta-test'.
$ ./gradlew clean check 
To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.10.2/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build 
> Task :clean
> Task :processResources
> Task :processTestResources
> Task :generateEffectiveLombokConfig
> Task :compileJava
> Task :classes
> Task :generateTestEffectiveLombokConfig
> Task :compileTestJava
> Task :testClasses

> Task :test FAILED

MyEntityRepositoryTest > saveFindAndUpdate() FAILED
    java.lang.AssertionError at MyEntityRepositoryTest.java:72

MyEntityRepositoryTest > save() FAILED
    java.lang.AssertionError at MyEntityRepositoryTest.java:42

6 tests completed, 2 failed

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///.../jakarta-persistence-weld-testing/build/reports/tests/test/index.html

* Try:
> Run with --scan to get full insights.

BUILD FAILED in 6s
8 actionable tasks: 8 executed

@gunnarmorling could validate this example as well.

manovotn commented 2 months ago

I see, thanks @x80486

I can see you are handling JPA and actually only need JTA bits. You could add those (well, most of them) by annotating the test with:

import com.arjuna.ats.jta.cdi.TransactionExtension;
// more imports...

@EnableAutoWeld
@AddBeanClasses(EntityManagerProducer.class)
@AddExtensions(TransactionExtension.class)
final class MyEntityRepositoryTest {
// test itself...

For which you need a dependency on narayana, so in gradle speech that should be something like testImplementation("org.jboss.narayana.jta:narayana-jta:7.0.2.Final").

But that seems to leave two tests failing and in both cases it seems that saved entity then cannot be found.