Skip to content

Commit 73a9320

Browse files
committed
Replace Guzzle MockHandler with Wiremock in HTTP tests
1 parent 359cecf commit 73a9320

File tree

6 files changed

+41
-56
lines changed

6 files changed

+41
-56
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ branches:
2727
- bad_implementation
2828
- bad_tests
2929
- integration_infra_medium_domain
30+
- integration_infra_medium_domain_wiremock
3031

3132
before_install:
3233
- make preinstall

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Many obscure changes are required in the tests, proving they do not help much du
2020
[(see Pull Request)](https://github.com/JMLamodiere/tdd-demo-forumphp2020/pull/13) split tests this way:
2121
- Domain logic (Application/Domain folders): medium Unit tests, mocking only infrastructure
2222
- Technical logic (Infrastructure folder): integration tests for each specific technology
23+
1. [integration_infra_medium_domain_wiremock](https://github.com/JMLamodiere/tdd-demo-forumphp2020/tree/integration_infra_medium_domain_wiremock) branch
24+
[(see Pull Request)](https://github.com/JMLamodiere/tdd-demo-forumphp2020/pull/14)
25+
only replaces [Guzzle MockHandler](https://docs.guzzlephp.org/en/stable/testing.html) with [Wiremock](#wiremock),
26+
decoupling HTTP tests with the library being used for HTTP calls.
2327
1. (todo...)
2428

2529
## API documentation

behat.yml.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ default:
66
kernel: '@kernel'
77
dbal: '@doctrine.dbal.default_connection'
88
wireMock: '@WireMock\Client\WireMock'
9+
accuweatherApiKey: '%%accuweather.apikey%%'
910

1011
extensions:
1112
Behat\Symfony2Extension:

config/packages/test/services.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
parameters:
2+
# See .env.test
3+
accuweather.apikey: '%env(ACCUWEATHER_API_KEY)%'
4+
15
services:
26
# default configuration for services in *this* file
37
_defaults:

features/bootstrap/FeatureContext.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,19 @@
1111

1212
class FeatureContext implements Context
1313
{
14-
// See .env.test
15-
private const ACCUWEATHER_API_KEY = 'accuweatherTestKey';
16-
1714
private KernelInterface $kernel;
1815
private Connection $dbal;
1916
private WireMock $wireMock;
2017
private ?Response $response;
18+
private string $accuweatherApiKey;
2119

22-
public function __construct(KernelInterface $kernel, Connection $dbal, WireMock $wireMock)
20+
public function __construct(KernelInterface $kernel, Connection $dbal, WireMock $wireMock, string $accuweatherApiKey)
2321
{
2422
$this->kernel = $kernel;
2523
$this->wireMock = $wireMock;
2624
Assert::assertTrue($this->wireMock->isAlive(), 'Wiremock should be alive');
2725
$this->dbal = $dbal;
26+
$this->accuweatherApiKey = $accuweatherApiKey;
2827
}
2928

3029
/**
@@ -41,7 +40,7 @@ public function resetState()
4140
*/
4241
public function currentTemperatureIs($temperature)
4342
{
44-
$uri = '/currentconditions/v1/623?apikey='.self::ACCUWEATHER_API_KEY;
43+
$uri = '/currentconditions/v1/623?apikey='.$this->accuweatherApiKey;
4544
$body = <<<EOD
4645
[{
4746
"LocalObservationDateTime": "2020-10-17T17:50:00+02:00",

tests/Infrastructure/Http/RestWeatherProviderTest.php

Lines changed: 27 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,35 @@
55
namespace App\Infrastructure\Http;
66

77
use App\Domain\CannotGetCurrentTemperature;
8-
use GuzzleHttp\Client;
9-
use GuzzleHttp\Exception\RequestException;
10-
use GuzzleHttp\Handler\MockHandler;
11-
use GuzzleHttp\HandlerStack;
12-
use GuzzleHttp\Promise\PromiseInterface;
13-
use GuzzleHttp\Psr7\Request;
14-
use GuzzleHttp\Psr7\Response;
15-
use PHPUnit\Framework\TestCase;
16-
use Prophecy\PhpUnit\ProphecyTrait;
17-
use Psr\Http\Message\ResponseInterface;
18-
use Throwable;
19-
20-
class RestWeatherProviderTest extends TestCase
21-
{
22-
use ProphecyTrait;
8+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
9+
use WireMock\Client\WireMock;
2310

24-
private MockHandler $guzzleMockHandler;
25-
private string $apiKey;
11+
class RestWeatherProviderTest extends KernelTestCase
12+
{
2613
private RestWeatherProvider $provider;
14+
private WireMock $wireMock;
15+
private string $currentConditionUri;
2716

2817
protected function setUp(): void
2918
{
30-
$this->guzzleMockHandler = new MockHandler();
31-
$guzzleClient = new Client(['handler' => new HandlerStack($this->guzzleMockHandler)]);
32-
33-
$this->apiKey = 'key';
34-
$this->provider = new RestWeatherProvider(
35-
$guzzleClient,
36-
$this->apiKey,
37-
new CurrentConditionDeserializer()
38-
);
19+
self::bootKernel();
20+
21+
$this->provider = self::$container->get(RestWeatherProvider::class);
22+
23+
$this->wireMock = self::$container->get(WireMock::class);
24+
self::assertTrue($this->wireMock->isAlive(), 'Wiremock should be alive');
25+
26+
$accuweatherApiKey = self::$container->getParameter('accuweather.apikey');
27+
$this->currentConditionUri = '/currentconditions/v1/623?apikey='.$accuweatherApiKey;
3928
}
4029

4130
public function testTemperatureIsExtractedFrom200Response()
4231
{
4332
// Given (Arrange)
44-
$this->givenAccuWeatherResponseIs(new Response(200, ['Content-Type' => 'application/json'], <<<EOD
33+
$this->wireMock->stubFor(WireMock::get(WireMock::urlEqualTo($this->currentConditionUri))
34+
->willReturn(WireMock::aResponse()
35+
->withHeader('Content-Type', 'application/json')
36+
->withBody(<<<EOD
4537
[{
4638
"LocalObservationDateTime": "2020-10-17T17:50:00+02:00",
4739
"EpochTime": 1602949800,
@@ -65,23 +57,21 @@ public function testTemperatureIsExtractedFrom200Response()
6557
"MobileLink": "http://m.accuweather.com/en/fr/paris/623/current-weather/623?lang=en-us",
6658
"Link": "http://www.accuweather.com/en/fr/paris/623/current-weather/623?lang=en-us"
6759
}]
68-
EOD));
60+
EOD)));
6961

7062
// When (Act)
7163
$result = $this->provider->getCurrentCelciusTemperature();
7264

7365
// Then (Assert)
7466
self::assertSame(37.2, $result);
75-
76-
$this->thenRequestSentShouldHaveBeen('GET', 'currentconditions/v1/623?apikey='.$this->apiKey);
7767
}
7868

7969
public function test404ResponseIsConvertedToDomainException()
8070
{
8171
// Given (Arrange)
82-
$this->givenAccuWeatherResponseIs(RequestException::create(
83-
new Request('GET', 'uri'),
84-
new Response(404)
72+
$this->wireMock->stubFor(WireMock::get(WireMock::urlEqualTo($this->currentConditionUri))
73+
->willReturn(WireMock::aResponse()
74+
->withStatus(404)
8575
));
8676

8777
// Then (Assert)
@@ -94,29 +84,15 @@ public function test404ResponseIsConvertedToDomainException()
9484
public function testInvalidBodyIsConvertedToDomainException()
9585
{
9686
// Given (Arrange)
97-
$this->givenAccuWeatherResponseIs(
98-
new Response(200, ['Content-Type' => 'application/json'], 'invalid body')
99-
);
87+
$this->wireMock->stubFor(WireMock::get(WireMock::urlEqualTo($this->currentConditionUri))
88+
->willReturn(WireMock::aResponse()
89+
->withHeader('Content-Type', 'application/json')
90+
->withBody('invalid body')));
10091

10192
// Then (Assert)
10293
$this->expectException(CannotGetCurrentTemperature::class);
10394

10495
// When (Act)
10596
$this->provider->getCurrentCelciusTemperature();
10697
}
107-
108-
/**
109-
* @param ResponseInterface|Throwable|PromiseInterface|callable $response
110-
*/
111-
private function givenAccuWeatherResponseIs($response)
112-
{
113-
$this->guzzleMockHandler->append($response);
114-
}
115-
116-
private function thenRequestSentShouldHaveBeen(string $method, string $uri)
117-
{
118-
$requestSent = $this->guzzleMockHandler->getLastRequest();
119-
self::assertSame($method, $requestSent->getMethod());
120-
self::assertSame($uri, (string) $requestSent->getUri());
121-
}
12298
}

0 commit comments

Comments
 (0)