Dies ist vielleicht schwieriger zu tun, aber ich glaube, es macht für lesbarere Tests. Hoffentlich hilfst du mir dabei, das zu vereinfachen, was ich beschreiben werde.
Meine Idee ist, HTTP-Anfragen stub. Unter Berücksichtigung von Facebook gibt es zwei davon: 1) /oauth/access_token
(um Zugriffstoken zu erhalten), 2) /me
(um Daten über den Benutzer zu erhalten).
Dafür habe ich angebracht vorübergehend php
-mitmproxy
vcr
Befestigung zu schaffen:
php
Sagen Sie HTTP-Proxy zu verwenden (fügen Sie die folgenden Zeilen in die .env
-Datei):
HTTP_PROXY=http://localhost:8080
HTTPS_PROXY=http://localhost:8080
Sagen php
Das Proxy-Zertifikat lautet: Fügen Sie openssl.cafile = /etc/php/mitmproxy-ca-cert.pem
zu php.ini
hinzu. Oder curl.cainfo
, für diese Angelegenheit.
- Neustart
php-fpm
.
- Start
mitmproxy
.
-
Machen Sie Ihren Browser durch
mitmproxy
auch verbunden.
Melden Sie sich mit Facebook bei der Website an, die Sie entwickeln (keine TDD hier).
Press z
in mitmproxy
(C
für mitmproxy
< 0,18) Anfrage (flow) Liste zu löschen, bevor sein, wenn nötig auf facebook umleiten. Alternativ können Sie auch f
(l
für mitmproxy
< 0.18) mit graph.facebook.com
verwenden, um zusätzliche Anforderungen herauszufiltern.
Beachten Sie, dass Sie für Twitter benötigen Sie league/oauth1-client
1.7 oder neuer. Der eine wechselte von zu guzzlehttp/guzzle
. Sonst können Sie sich nicht anmelden.
Kopieren Sie Daten von mimtproxy
zu tests/fixtures/facebook
. Ich benutzte yaml
Format und hier ist, wie es aussieht:
-
request:
method: GET
url: https://graph.facebook.com/oauth/access_token?client_id=...&client_secret=...&code=...&redirect_uri=...
response:
status:
http_version: '1.1'
code: 200
message: OK
body: access_token=...&expires=...
-
request:
method: GET
url: https://graph.facebook.com/v2.5/me?access_token=...&appsecret_proof=...&fields=first_name,last_name,email,gender,verified
response:
status:
http_version: '1.1'
code: 200
message: OK
body: '{"first_name":"...","last_name":"...","email":"...","gender":"...","verified":true,"id":"..."}'
Dafür Sie E
Befehl verwenden können, wenn Sie mitmproxy
> = 0,18 haben. Verwenden Sie alternativ den Befehl P
. Es kopiert die Anfrage/Antwort in die Zwischenablage. Wenn Sie mitmproxy
möchten, um sie direkt in Datei zu speichern, können Sie es mit DISPLAY= mitmproxy
ausführen.
Ich sehe keine Möglichkeit php-vcr
's Aufnahmemöglichkeiten zu verwenden, da ich nicht den gesamten Arbeitsablauf teste.
Damit konnte ich die folgenden Tests (und ja, sie sind gut mit all den durch Punkte ersetzt Werte, fühlen sich frei, wie zu kopieren) schreiben.
Beachten Sie bitte, Leuchten hängen von der laravel/socialite
Version ab. Ich hatte ein Problem mit Facebook. In Version 2.0.16
laravel/socialite
gestartet post requests, um Zugriffstoken zu erhalten. Auch gibt es api version in Facebook-URLs.
Diese Vorrichtungen sind für 2.0.14
. Eine Möglichkeit, damit umzugehen, ist laravel/socialite
Abhängigkeit in require-dev
Abschnitt composer.json
Datei auch (mit strenger Versionsspezifikation) zu gewährleisten, dass socialite
der richtigen Version in der Entwicklungsumgebung ist (composer
wird hoffentlich ignorieren die in require-dev
Abschnitt in der Produktionsumgebung .) Unter Berücksichtigung Sie tun composer install --no-dev
in der Produktionsumgebung.
AuthController_HandleFacebookCallbackTest.php
:
<?php
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Auth;
use VCR\VCR;
use App\User;
class AuthController_HandleFacebookCallbackTest extends TestCase
{
use DatabaseTransactions;
static function setUpBeforeClass()
{
VCR::configure()->enableLibraryHooks(['stream_wrapper', 'curl'])
->enableRequestMatchers([
'method',
'url',
]);
}
/**
* @vcr facebook
*/
function testCreatesUserWithCorrespondingName()
{
$this->doCallbackRequest();
$this->assertEquals('John Doe', User::first()->name);
}
/**
* @vcr facebook
*/
function testCreatesUserWithCorrespondingEmail()
{
$this->doCallbackRequest();
$this->assertEquals('[email protected]', User::first()->email);
}
/**
* @vcr facebook
*/
function testCreatesUserWithCorrespondingFbId()
{
$this->doCallbackRequest();
$this->assertEquals(123, User::first()->fb_id);
}
/**
* @vcr facebook
*/
function testCreatesUserWithFbData()
{
$this->doCallbackRequest();
$this->assertNotEquals('', User::first()->fb_data);
}
/**
* @vcr facebook
*/
function testRedirectsToHomePage()
{
$this->doCallbackRequest();
$this->assertRedirectedTo('/');
}
/**
* @vcr facebook
*/
function testAuthenticatesUser()
{
$this->doCallbackRequest();
$this->assertEquals(User::first()->id, Auth::user()->id);
}
/**
* @vcr facebook
*/
function testDoesntCreateUserIfAlreadyExists()
{
$user = factory(User::class)->create([
'fb_id' => 123,
]);
$this->doCallbackRequest();
$this->assertEquals(1, User::count());
}
function doCallbackRequest()
{
return $this->withSession([
'state' => '...',
])->get('/auth/facebook/callback?' . http_build_query([
'state' => '...',
]));
}
}
tests/fixtures/facebook
:
-
request:
method: GET
url: https://graph.facebook.com/oauth/access_token
response:
status:
http_version: '1.1'
code: 200
message: OK
body: access_token=...
-
request:
method: GET
url: https://graph.facebook.com/v2.5/me
response:
status:
http_version: '1.1'
code: 200
message: OK
body: '{"first_name":"John","last_name":"Doe","email":"john.doe\u0040gmail.com","id":"123"}'
AuthController_HandleTwitterCallbackTest.php
:
<?php
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Auth;
use VCR\VCR;
use League\OAuth1\Client\Credentials\TemporaryCredentials;
use App\User;
class AuthController_HandleTwitterCallbackTest extends TestCase
{
use DatabaseTransactions;
static function setUpBeforeClass()
{
VCR::configure()->enableLibraryHooks(['stream_wrapper', 'curl'])
->enableRequestMatchers([
'method',
'url',
]);
}
/**
* @vcr twitter
*/
function testCreatesUserWithCorrespondingName()
{
$this->doCallbackRequest();
$this->assertEquals('joe', User::first()->name);
}
/**
* @vcr twitter
*/
function testCreatesUserWithCorrespondingTwId()
{
$this->doCallbackRequest();
$this->assertEquals(123, User::first()->tw_id);
}
/**
* @vcr twitter
*/
function testCreatesUserWithTwData()
{
$this->doCallbackRequest();
$this->assertNotEquals('', User::first()->tw_data);
}
/**
* @vcr twitter
*/
function testRedirectsToHomePage()
{
$this->doCallbackRequest();
$this->assertRedirectedTo('/');
}
/**
* @vcr twitter
*/
function testAuthenticatesUser()
{
$this->doCallbackRequest();
$this->assertEquals(User::first()->id, Auth::user()->id);
}
/**
* @vcr twitter
*/
function testDoesntCreateUserIfAlreadyExists()
{
$user = factory(User::class)->create([
'tw_id' => 123,
]);
$this->doCallbackRequest();
$this->assertEquals(1, User::count());
}
function doCallbackRequest()
{
$temporaryCredentials = new TemporaryCredentials();
$temporaryCredentials->setIdentifier('...');
$temporaryCredentials->setSecret('...');
return $this->withSession([
'oauth.temp' => $temporaryCredentials,
])->get('/auth/twitter/callback?' . http_build_query([
'oauth_token' => '...',
'oauth_verifier' => '...',
]));
}
}
tests/fixtures/twitter
:
AuthController_HandleGoogleCallbackTest.php
:
<?php
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Auth;
use VCR\VCR;
use App\User;
class AuthController_HandleGoogleCallbackTest extends TestCase
{
use DatabaseTransactions;
static function setUpBeforeClass()
{
VCR::configure()->enableLibraryHooks(['stream_wrapper', 'curl'])
->enableRequestMatchers([
'method',
'url',
]);
}
/**
* @vcr google
*/
function testCreatesUserWithCorrespondingName()
{
$this->doCallbackRequest();
$this->assertEquals('John Doe', User::first()->name);
}
/**
* @vcr google
*/
function testCreatesUserWithCorrespondingEmail()
{
$this->doCallbackRequest();
$this->assertEquals('[email protected]', User::first()->email);
}
/**
* @vcr google
*/
function testCreatesUserWithCorrespondingGpId()
{
$this->doCallbackRequest();
$this->assertEquals(123, User::first()->gp_id);
}
/**
* @vcr google
*/
function testCreatesUserWithGpData()
{
$this->doCallbackRequest();
$this->assertNotEquals('', User::first()->gp_data);
}
/**
* @vcr google
*/
function testRedirectsToHomePage()
{
$this->doCallbackRequest();
$this->assertRedirectedTo('/');
}
/**
* @vcr google
*/
function testAuthenticatesUser()
{
$this->doCallbackRequest();
$this->assertEquals(User::first()->id, Auth::user()->id);
}
/**
* @vcr google
*/
function testDoesntCreateUserIfAlreadyExists()
{
$user = factory(User::class)->create([
'gp_id' => 123,
]);
$this->doCallbackRequest();
$this->assertEquals(1, User::count());
}
function doCallbackRequest()
{
return $this->withSession([
'state' => '...',
])->get('/auth/google/callback?' . http_build_query([
'state' => '...',
]));
}
}
tests/fixtures/google
:
-
request:
method: POST
url: https://accounts.google.com/o/oauth2/token
response:
status:
http_version: '1.1'
code: 200
message: OK
body: access_token=...
-
request:
method: GET
url: https://www.googleapis.com/plus/v1/people/me
response:
status:
http_version: '1.1'
code: 200
message: OK
body: '{"emails":[{"value":"[email protected]"}],"id":"123","displayName":"John Doe","image":{"url":"https://googleusercontent.com/photo.jpg"}}'
Hinweis. Vergewissern Sie sich, php-vcr/phpunit-testlistener-vcr
erforderlich ist, und dass Sie die folgende Zeile in der phpunit.xml
:
<listeners>
<listener class="PHPUnit_Util_Log_VCR" file="vendor/php-vcr/phpunit-testlistener-vcr/PHPUnit/Util/Log/VCR.php"/>
</listeners>
Es gab auch ein Problem mit $_SERVER['HTTP_HOST']
nicht gesetzt werden, wenn die Tests ausgeführt werden.Ich spreche über config/services.php
Datei hier, nämlich über Redirect URL. Ich habe es so behandelt:
<?php
$app = include dirname(__FILE__) . '/app.php';
return [
...
'facebook' => [
...
'redirect' => (isset($_SERVER['HTTP_HOST']) ? 'http://' . $_SERVER['HTTP_HOST'] : $app['url']) . '/auth/facebook/callback',
],
];
Nicht besonders schön, aber ich habe es versäumt, einen besseren Weg zu finden. Ich würde dort config('app.url')
verwenden, aber es funktioniert nicht in den Config-Dateien.
UPD Sie können setUpBeforeClass
Teil durch Entfernen dieser Methode, Ausführen von Tests und Aktualisieren der Anfrage Teil der Fixtures mit was vcr Datensätze loswerden. Eigentlich könnte die ganze Sache mit vcr
allein gemacht werden (keine mitmproxy
).
Ich denke, Sie könnten wollen 'Socialite :: sollteReceive ('Treiber-> Redirect')'. – ceejayoz
@ceejayoz Das funktioniert nicht, es beschwert sich, dass es die Methode 'Treiber-> Redirect' nicht sieht –