1
|
|
|
<?php declare(strict_types = 1); |
2
|
|
|
|
3
|
|
|
namespace TomCizek\ResponseRecorder\Tests\Application; |
4
|
|
|
|
5
|
|
|
use Closure; |
6
|
|
|
use Exception; |
7
|
|
|
use PHPUnit\Framework\TestCase; |
8
|
|
|
use Prooph\ServiceBus\EventBus; |
9
|
|
|
use Prooph\ServiceBus\Exception\CommandDispatchException; |
10
|
|
|
use Psr\Log\NullLogger; |
11
|
|
|
use TomCizek\ResponseRecorder\Application\ResponseRecorder; |
12
|
|
|
use TomCizek\ResponseRecorder\Application\ResponseRecorder\BasicMutationResponse; |
13
|
|
|
use TomCizek\ResponseRecorder\Application\ResponseRecorder\MutationResponse\ErrorCollection\ShowableMutationError; |
14
|
|
|
use TomCizek\ResponseRecorder\Tests\FakeImplementations\TestDomainEvent; |
15
|
|
|
use TomCizek\ResponseRecorder\Tests\FakeImplementations\TestShowableTranslatableException; |
16
|
|
|
use TomCizek\ResponseRecorder\Tests\FakeImplementations\TestTranslatableDomainErrorDomainEvent; |
17
|
|
|
|
18
|
|
|
class ResponseRecorderTest extends TestCase |
19
|
|
|
{ |
20
|
|
|
/** @var ResponseRecorder */ |
21
|
|
|
private $sut; |
22
|
|
|
|
23
|
|
|
/** @var EventBus */ |
24
|
|
|
private $eventBus; |
25
|
|
|
|
26
|
|
|
public function setUp(): void |
27
|
|
|
{ |
28
|
|
|
parent::setUp(); |
29
|
|
|
|
30
|
|
|
$this->eventBus = new EventBus(); |
31
|
|
|
|
32
|
|
|
$this->sut = new ResponseRecorder($this->eventBus, new NullLogger()); |
33
|
|
|
|
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
public function testRecordOn_EmptyFunction_ShouldReturnEmptyResponse(): void |
37
|
|
|
{ |
38
|
|
|
$response = $this->whenRecordOnFunctionThat( |
39
|
|
|
$this->doNothing() |
40
|
|
|
); |
41
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 0); |
42
|
|
|
$this->thenCountOfDomainEventsIs($response, 0); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
View Code Duplication |
public function testRecordOn_FunctionThrowingFatalError_ShouldReturnResponseWithOneFatalError(): void |
|
|
|
|
46
|
|
|
{ |
47
|
|
|
$response = $this->whenRecordOnFunctionThat( |
48
|
|
|
$this->throwFatalException() |
49
|
|
|
); |
50
|
|
|
|
51
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 1); |
52
|
|
|
$this->thenCountOfDomainEventsIs($response, 0); |
53
|
|
|
$this->thenFirstErrorHasMessage($response, ResponseRecorder::FATAL_ERROR_MESSAGE); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
public function testRecordOn_FunctionThrowingShowableError_ShouldReturnResponseWithShowableError(): void |
57
|
|
|
{ |
58
|
|
|
|
59
|
|
|
$testMessage = 'test_message'; |
60
|
|
|
$testParams = ['foo' => 'bar']; |
61
|
|
|
|
62
|
|
|
$response = $this->whenRecordOnFunctionThat( |
63
|
|
|
$this->throwShowableException($testMessage, $testParams) |
64
|
|
|
); |
65
|
|
|
|
66
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 1); |
67
|
|
|
$this->thenCountOfDomainEventsIs($response, 0); |
68
|
|
|
$this->thenFirstErrorHasMessage($response, $testMessage); |
69
|
|
|
$this->thenFirstErrorHasMessageParams($response, $testParams); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
public function testRecordOn_FunctionThrowingCommandDispatchExceptionWithPreviousShowableException_ShouldReturnResponseWithShowableError( |
73
|
|
|
): void |
74
|
|
|
{ |
75
|
|
|
$testMessage = 'test_message'; |
76
|
|
|
$testParams = ['foo' => 'bar']; |
77
|
|
|
|
78
|
|
|
$response = $this->whenRecordOnFunctionThat( |
79
|
|
|
$this->throwCommandDispatchExceptionWithPreviousShowable($testMessage, $testParams) |
80
|
|
|
); |
81
|
|
|
|
82
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 1); |
83
|
|
|
$this->thenCountOfDomainEventsIs($response, 0); |
84
|
|
|
$this->thenFirstErrorHasMessage($response, $testMessage); |
85
|
|
|
$this->thenFirstErrorHasMessageParams($response, $testParams); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
View Code Duplication |
public function testRecordOn_FunctionThrowingCommandDispatchExceptionWithPreviousFatalException_ShouldReturnResponseWithShowableFatalError( |
|
|
|
|
89
|
|
|
): void |
90
|
|
|
{ |
91
|
|
|
$response = $this->whenRecordOnFunctionThat( |
92
|
|
|
$this->throwCommandDispatchExceptionWithPreviousFatal() |
93
|
|
|
); |
94
|
|
|
|
95
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 1); |
96
|
|
|
$this->thenCountOfDomainEventsIs($response, 0); |
97
|
|
|
$this->thenFirstErrorHasMessage($response, ResponseRecorder::FATAL_ERROR_MESSAGE); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
public function testRecordOn_FunctionDispatchingErrorDomainEvent_ShouldReturnResponseWithShowableError(): void |
101
|
|
|
{ |
102
|
|
|
$testPayload = ['test_payload']; |
103
|
|
|
$testErrorDomainEvent = new TestTranslatableDomainErrorDomainEvent($testPayload); |
104
|
|
|
|
105
|
|
|
$eventBus = $this->eventBus; |
106
|
|
|
$response = $this->whenRecordOnFunctionThat( |
107
|
|
|
$this->dispatchMessageEventOnce($testErrorDomainEvent, $eventBus) |
108
|
|
|
); |
109
|
|
|
|
110
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 1); |
111
|
|
|
$this->thenCountOfDomainEventsIs($response, 1); |
112
|
|
|
$this->thenFirstErrorHasMessage($response, TestTranslatableDomainErrorDomainEvent::TEST_ERROR_MESSAGE); |
113
|
|
|
$this->thenFirstErrorHasMessageParams($response, TestTranslatableDomainErrorDomainEvent::TEST_ERROR_MESSAGE_PARAMS); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
View Code Duplication |
public function testRecordOn_FunctionDispatchingTwoErrorDomainEventAndThrowingException_ShouldReturnResponseWith2EventsAnd3Errors( |
|
|
|
|
117
|
|
|
): void |
118
|
|
|
{ |
119
|
|
|
$testPayload = ['test_payload']; |
120
|
|
|
$testErrorDomainEvent = new TestTranslatableDomainErrorDomainEvent($testPayload); |
121
|
|
|
|
122
|
|
|
$eventBus = $this->eventBus; |
123
|
|
|
$response = $this->whenRecordOnFunctionThat( |
124
|
|
|
$this->dispatchMessageTwoTimesAndThrowException($testErrorDomainEvent, $eventBus) |
125
|
|
|
); |
126
|
|
|
|
127
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 3); |
128
|
|
|
$this->thenCountOfDomainEventsIs($response, 2); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
public function testRecordOn_FunctionDispatchingStringEvent_ShouldReturnEmptyResponse(): void |
132
|
|
|
{ |
133
|
|
|
|
134
|
|
|
$testMessage = 'test_message'; |
135
|
|
|
|
136
|
|
|
$eventBus = $this->eventBus; |
137
|
|
|
$response = $this->whenRecordOnFunctionThat( |
138
|
|
|
$this->dispatchMessageEventOnce($testMessage, $eventBus) |
139
|
|
|
); |
140
|
|
|
|
141
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 0); |
142
|
|
|
$this->thenCountOfDomainEventsIs($response, 0); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
View Code Duplication |
public function testRecordOn_FunctionDispatchingEvent_ShouldReturnResponseWithEvent(): void |
|
|
|
|
146
|
|
|
{ |
147
|
|
|
$testPayload = ['test_payload']; |
148
|
|
|
$testDomainEvent = new TestDomainEvent($testPayload); |
149
|
|
|
|
150
|
|
|
$eventBus = $this->eventBus; |
151
|
|
|
$response = $this->whenRecordOnFunctionThat( |
152
|
|
|
$this->dispatchMessageEventOnce($testDomainEvent, $eventBus) |
153
|
|
|
); |
154
|
|
|
|
155
|
|
|
$this->thenCountOfErrorsOnResponseIs($response, 0); |
156
|
|
|
$this->thenCountOfDomainEventsIs($response, 1); |
157
|
|
|
$this->thenEventIsTestDomainEventWithPayoad($response, $testPayload); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
private function whenRecordOnFunctionThat(Closure $doSomething): BasicMutationResponse |
161
|
|
|
{ |
162
|
|
|
return $this->sut->recordOn($doSomething); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
private function dispatchMessageEventOnce($domainEventMessage, EventBus $eventBus): Closure |
166
|
|
|
{ |
167
|
|
|
return function () use ($domainEventMessage, $eventBus) { |
168
|
|
|
$eventBus->dispatch($domainEventMessage); |
169
|
|
|
}; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
private function dispatchMessageTwoTimesAndThrowException($domainEventMessage, EventBus $eventBus): Closure |
173
|
|
|
{ |
174
|
|
|
return function () use ($domainEventMessage, $eventBus) { |
175
|
|
|
$eventBus->dispatch($domainEventMessage); |
176
|
|
|
$eventBus->dispatch($domainEventMessage); |
177
|
|
|
throw new Exception(); |
178
|
|
|
}; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
private function throwFatalException(): Closure |
182
|
|
|
{ |
183
|
|
|
return function () { |
184
|
|
|
throw new Exception(); |
185
|
|
|
}; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
private function throwShowableException($domainEventMessage, array $testParams): Closure |
189
|
|
|
{ |
190
|
|
|
return function () use ($domainEventMessage, $testParams) { |
191
|
|
|
throw new TestShowableTranslatableException($domainEventMessage, $testParams); |
192
|
|
|
}; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
private function throwCommandDispatchExceptionWithPreviousShowable($domainEventMessage, array $testParams): Closure |
196
|
|
|
{ |
197
|
|
|
return function () use ($domainEventMessage, $testParams) { |
198
|
|
|
$previous = new TestShowableTranslatableException($domainEventMessage, $testParams); |
199
|
|
|
throw new CommandDispatchException('', 0, $previous); |
200
|
|
|
}; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
private function throwCommandDispatchExceptionWithPreviousFatal(): Closure |
204
|
|
|
{ |
205
|
|
|
return function () { |
206
|
|
|
$previous = new Exception(); |
207
|
|
|
throw new CommandDispatchException('', 0, $previous); |
208
|
|
|
}; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
private function thenCountOfErrorsOnResponseIs(BasicMutationResponse $response, int $expectedCount): void |
212
|
|
|
{ |
213
|
|
|
self::assertCount($expectedCount, $response->getErrors()); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
protected function thenCountOfDomainEventsIs(BasicMutationResponse $response, int $expectedCount): void |
217
|
|
|
{ |
218
|
|
|
self::assertCount($expectedCount, $response->getDomainEvents()); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
View Code Duplication |
protected function thenFirstErrorHasMessage(BasicMutationResponse $response, $message): void |
|
|
|
|
222
|
|
|
{ |
223
|
|
|
$error = $response->getErrors()->getAll()[0]; |
224
|
|
|
|
225
|
|
|
self::assertInstanceOf(ShowableMutationError::class, $error); |
226
|
|
|
self::assertEquals($message, $error->getErrorMessage()); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
View Code Duplication |
private function thenFirstErrorHasMessageParams(BasicMutationResponse $response, $params) |
|
|
|
|
230
|
|
|
{ |
231
|
|
|
$error = $response->getErrors()->getAll()[0]; |
232
|
|
|
|
233
|
|
|
self::assertInstanceOf(ShowableMutationError::class, $error); |
234
|
|
|
self::assertEquals($params, $error->getErrorMessageParams()); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
protected function thenEventIsTestDomainEventWithPayoad(BasicMutationResponse $response, $testPayload): void |
238
|
|
|
{ |
239
|
|
|
$event = $response->getDomainEvents()->getAll()[0]; |
240
|
|
|
|
241
|
|
|
self::assertInstanceOf(TestDomainEvent::class, $event); |
242
|
|
|
self::assertEquals($testPayload, $event->payload()); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
protected function doNothing(): Closure |
246
|
|
|
{ |
247
|
|
|
return function () { |
248
|
|
|
}; |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.