GH-1226: Fix Test Harness
Resolves https://github.com/spring-projects/spring-amqp/issues/1226 https://github.com/spring-projects/spring-amqp/issues/1157 changed the way we spy listeners - to support CGLIB proxies (e.g. `@Transactional`). Instead of spying the listener, it mocks the listener and sets a default answer to call the real method on the delegate. This broke when users used other answers, such as those provided by the framework. Change the provided answers to subclass `ForwardsInvocation`. Also fix `ConcurrentModificationException` in `getExceptions()`. **cherry-pick to 2.2.x, 2.1.x**
This commit is contained in:
committed by
Artem Bilan
parent
9d6ce0da33
commit
c40b2b53bc
@@ -74,13 +74,13 @@ The following example shows how to use `LatchCountDownAndCallRealMethodAnswer`:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(2);
|
||||
LatchCountDownAndCallRealMethodAnswer answer = this.harness.getLatchAnswerFor("myListener", 2);
|
||||
doAnswer(answer)
|
||||
.when(listener).foo(anyString(), anyString());
|
||||
|
||||
...
|
||||
|
||||
assertTrue(answer.getLatch().await(10, TimeUnit.SECONDS));
|
||||
assertThat(answer.await(10)).isTrue();
|
||||
----
|
||||
====
|
||||
|
||||
@@ -126,6 +126,7 @@ assertEquals("thingthing", thing.thing("thing"));
|
||||
Starting with version 2.2.3, the answers capture any exceptions thrown by the method under test.
|
||||
Use `answer.getExceptions()` to get a reference to them.
|
||||
|
||||
When used in conjunction with the <<test-harness>> use `harness.getLambdaAnswerFor("listenerId", true, ...)` to get a properly constructed answer for the listener.
|
||||
|
||||
[[test-harness]]
|
||||
==== `@RabbitListenerTest` and `RabbitListenerTestHarness`
|
||||
@@ -197,13 +198,13 @@ public class MyTests {
|
||||
Listener listener = this.harness.getSpy("bar");
|
||||
assertNotNull(listener);
|
||||
|
||||
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(2); <3>
|
||||
LatchCountDownAndCallRealMethodAnswer answer = this.harness.getLatchAnswerFor("bar", 2); <3>
|
||||
doAnswer(answer).when(listener).foo(anyString(), anyString()); <4>
|
||||
|
||||
this.rabbitTemplate.convertAndSend(this.queue2.getName(), "bar");
|
||||
this.rabbitTemplate.convertAndSend(this.queue2.getName(), "baz");
|
||||
|
||||
assertTrue(answer.getLatch().await(10, TimeUnit.SECONDS));
|
||||
assertTrue(answer.await(10));
|
||||
verify(listener).foo("bar", this.queue2.getName());
|
||||
verify(listener).foo("baz", this.queue2.getName());
|
||||
}
|
||||
@@ -220,6 +221,7 @@ suspended in the `RabbitTemplate` waiting for the reply.
|
||||
<3> In this case, we're only using a send operation so we need a latch to wait for the asynchronous call to the listener
|
||||
on the container thread.
|
||||
We use one of the link:#mockito-answer[Answer<?>] implementations to help with that.
|
||||
IMPORTANT: Due to the way the listener is spied, it is important to use `harness.getLatchAnswerFor()` to get a properly configured answer for the spy.
|
||||
|
||||
<4> Configure the spy to invoke the `Answer`.
|
||||
====
|
||||
@@ -311,6 +313,9 @@ to suspend the test thread.
|
||||
<5> When the listener throws an exception, it is available in the `throwable` property of the invocation data.
|
||||
====
|
||||
|
||||
IMPORTANT: When using custom `Answer<?>` s with the harness, in order to operate properly, such answers should subclass `ForwardsInvocation` and get the actual listener (not the spy) from the harness (`getDelegate("myListener")`) and call `super.answer(invocation)`.
|
||||
See the provided <<mockito-answer>> source code for examples.
|
||||
|
||||
[[test-template]]
|
||||
==== Using `TestRabbitTemplate`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user