Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifies SpringListener to include Spring's Test Listeners #887

Merged
merged 1 commit into from
Jul 16, 2019

Conversation

LeoColman
Copy link
Member

Originally, our SpringLister would only execute one part of the Spring Test Context's API. This was insufficient for some of Spring's implementations, such as the TestExecutionListener api.

This commit changes the way the listener works to enable that kind of listener. It was very similar to our listener execution, so we just had to hook the executions.

Users that didn't use these features before won't be impacted in any way.

Implements #886

@LeoColman LeoColman requested a review from sksamuel July 13, 2019 04:02
@LeoColman
Copy link
Member Author

I'm not completely sure this will solve all the issues, but I know that now the listeners are being executed.

I'll ask my peer (he reported that this wasn't working) to take a look and see if this is likely to solve his bug


override fun afterTestClass(testContext: TestContext) {
count++
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each of these counts should be separate otherwise we don't know if the correct ones were invoked just that the correct quantity was.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one. I made the change and found a bug because of it.

@LeoColman LeoColman force-pushed the feature/886-spring-test-listener branch from 736a670 to 016d4db Compare July 16, 2019 13:54
Originally, our SpringLister would only execute one part of the Spring Test Context's API. This was insufficient for some of Spring's implementations, such as the TestExecutionListener api.

This commit changes the way the listener works to enable that kind of listener. It was very similar to our listener execution, so we just had to hook the executions.

Users that didn't use these features before won't be impacted in any way.

Implements #886
@LeoColman LeoColman force-pushed the feature/886-spring-test-listener branch from 016d4db to 419ae8c Compare July 16, 2019 13:55
@LeoColman
Copy link
Member Author

I think this is ready, @sksamuel

@LeoColman LeoColman requested a review from sksamuel July 16, 2019 13:57
@sksamuel
Copy link
Member

sksamuel commented Jul 16, 2019 via email

@LeoColman LeoColman merged commit d49f200 into master Jul 16, 2019
@LeoColman LeoColman deleted the feature/886-spring-test-listener branch July 16, 2019 14:19
LeoColman added a commit that referenced this pull request Aug 23, 2019
More information at #950

Spring executes transactions (and this include anything inside @DataJpaTest) through a Listener called TransactionalTestExecutionListener. This comes pre-registered with a SpringBootTest, and KotlinTest was executing this listener correctly as per #887.

However, only executing the Listener wasn't enough, as it couldn't autowire the EntityManager. Initially, this was happening because our SpringListener had a fake "test method" that was a pointer to java.lang.Object.hashcode method. We made this hack to allow us to execute code inside Spring Test Framework, and it seemed fine on our tests.

Due to hashcode being a java.lang.Object method, Spring couldn't find the transaction attribute, as it verified directly that the method wasn't from Java Object.

With this in mind, we must use an object from another class. My first attempt was to use a dummy method, declared in the SpringListener itself. But this also wouldn't work, as the listener would never find the TransactionAttribute, as the method doesn't (and shouldn't) declare a @transaction, and SpringListener also didn't declare that annotation. The only way to have a method with that annotation would be inside user's Spec definition, where the user would choose it.

We don't have methods, as we define everything through a DSL. But that didn't seem an issue, as Spring's Listener would get the Transaction Attribute from the method's class if it doesn't declare it. @DataJpaTest already declare transaction attributes, so if we managed to get a method inside it, it would work without having to declare @transaction.

If we could guarantee that our users were overriding a method, we could get its reference, but we couldn't force that, and referecing a method from Spec wouldn't work (as Spec doesn't declare the attributes).

The only way to solve this issue that I found was to inject a dummy method into the class, and get it through reflection, so that Spring Listener would correctly find the Transaction Attributes, and that's what I've done.

Fixes #950
LeoColman added a commit that referenced this pull request Aug 23, 2019
More information at #950

Spring executes transactions (and this include anything inside @DataJpaTest) through a Listener called TransactionalTestExecutionListener. This comes pre-registered with a SpringBootTest, and KotlinTest was executing this listener correctly as per #887.

However, only executing the Listener wasn't enough, as it couldn't autowire the EntityManager. Initially, this was happening because our SpringListener had a fake "test method" that was a pointer to java.lang.Object.hashcode method. We made this hack to allow us to execute code inside Spring Test Framework, and it seemed fine on our tests.

Due to hashcode being a java.lang.Object method, Spring couldn't find the transaction attribute, as it verified directly that the method wasn't from Java Object.

With this in mind, we must use an object from another class. My first attempt was to use a dummy method, declared in the SpringListener itself. But this also wouldn't work, as the listener would never find the TransactionAttribute, as the method doesn't (and shouldn't) declare a @transaction, and SpringListener also didn't declare that annotation. The only way to have a method with that annotation would be inside user's Spec definition, where the user would choose it.

We don't have methods, as we define everything through a DSL. But that didn't seem an issue, as Spring's Listener would get the Transaction Attribute from the method's class if it doesn't declare it. @DataJpaTest already declare transaction attributes, so if we managed to get a method inside it, it would work without having to declare @transaction.

If we could guarantee that our users were overriding a method, we could get its reference, but we couldn't force that, and referecing a method from Spec wouldn't work (as Spec doesn't declare the attributes).

The only way to solve this issue that I found was to inject a dummy method into the class, and get it through reflection, so that Spring Listener would correctly find the Transaction Attributes, and that's what I've done.

Fixes #950
sksamuel pushed a commit that referenced this pull request Aug 25, 2019
…#953)

More information at #950

Spring executes transactions (and this include anything inside @DataJpaTest) through a Listener called TransactionalTestExecutionListener. This comes pre-registered with a SpringBootTest, and KotlinTest was executing this listener correctly as per #887.

However, only executing the Listener wasn't enough, as it couldn't autowire the EntityManager. Initially, this was happening because our SpringListener had a fake "test method" that was a pointer to java.lang.Object.hashcode method. We made this hack to allow us to execute code inside Spring Test Framework, and it seemed fine on our tests.

Due to hashcode being a java.lang.Object method, Spring couldn't find the transaction attribute, as it verified directly that the method wasn't from Java Object.

With this in mind, we must use an object from another class. My first attempt was to use a dummy method, declared in the SpringListener itself. But this also wouldn't work, as the listener would never find the TransactionAttribute, as the method doesn't (and shouldn't) declare a @transaction, and SpringListener also didn't declare that annotation. The only way to have a method with that annotation would be inside user's Spec definition, where the user would choose it.

We don't have methods, as we define everything through a DSL. But that didn't seem an issue, as Spring's Listener would get the Transaction Attribute from the method's class if it doesn't declare it. @DataJpaTest already declare transaction attributes, so if we managed to get a method inside it, it would work without having to declare @transaction.

If we could guarantee that our users were overriding a method, we could get its reference, but we couldn't force that, and referecing a method from Spec wouldn't work (as Spec doesn't declare the attributes).

The only way to solve this issue that I found was to inject a dummy method into the class, and get it through reflection, so that Spring Listener would correctly find the Transaction Attributes, and that's what I've done.

Fixes #950
LeoColman added a commit that referenced this pull request Sep 20, 2019
…#953)

More information at #950

Spring executes transactions (and this include anything inside @DataJpaTest) through a Listener called TransactionalTestExecutionListener. This comes pre-registered with a SpringBootTest, and KotlinTest was executing this listener correctly as per #887.

However, only executing the Listener wasn't enough, as it couldn't autowire the EntityManager. Initially, this was happening because our SpringListener had a fake "test method" that was a pointer to java.lang.Object.hashcode method. We made this hack to allow us to execute code inside Spring Test Framework, and it seemed fine on our tests.

Due to hashcode being a java.lang.Object method, Spring couldn't find the transaction attribute, as it verified directly that the method wasn't from Java Object.

With this in mind, we must use an object from another class. My first attempt was to use a dummy method, declared in the SpringListener itself. But this also wouldn't work, as the listener would never find the TransactionAttribute, as the method doesn't (and shouldn't) declare a @transaction, and SpringListener also didn't declare that annotation. The only way to have a method with that annotation would be inside user's Spec definition, where the user would choose it.

We don't have methods, as we define everything through a DSL. But that didn't seem an issue, as Spring's Listener would get the Transaction Attribute from the method's class if it doesn't declare it. @DataJpaTest already declare transaction attributes, so if we managed to get a method inside it, it would work without having to declare @transaction.

If we could guarantee that our users were overriding a method, we could get its reference, but we couldn't force that, and referecing a method from Spec wouldn't work (as Spec doesn't declare the attributes).

The only way to solve this issue that I found was to inject a dummy method into the class, and get it through reflection, so that Spring Listener would correctly find the Transaction Attributes, and that's what I've done.

Fixes #950
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants