phpunit elevato alla symfony2
TRANSCRIPT
Eugenio Pombi
Symfony Day 05 October 2012
nerd2business.net
PHPUnit elevato alla Symfony2
@euxpom
Symfony2 Functional testing tools
Symfony\Bundle\FrameworkBundle\Client
Symfony\Bundle\FrameworkBundle\Crawler
Symfony\Component\HttpKernel\Profiler\Profile
Symfony\Bundle\FrameworkBundle\Client
Symfony\Bundle\FrameworkBundle\Crawler
Symfony\Component\HttpKernel\Profiler\Profile
Symfony\Bundle\DoctrineFixturesBundle
Profiler
config ->getBundles() ->getEnv()request ->getRouteParams() ->getController()exception ->hasException()events ->GetCalledListeners() ->getNotCalledListeners()logger ->CountErrors() ->getLogs()
time ->getTotalTime()memory ->getMemory()router ->getRedirect()security ->getUser() ->getRoles() ->isAuthenticated()swiftmailer ->getMessageCount() ->getMessages()
Doctrine profiler
db ->getQueryCount() ->getTime() ->getQueries()
query ['sql'] ['params'] ['types'] ['executionMS']
Stubbing
An example with Paypal
namespace JMS\Payment\PaypalBundle\Client;
class Client { [...] public function request(Request $request) { [...] // perform the request if (false === $returnTransfer = curl_exec($curl)) { throw new CommunicationException( 'cURL Error: '.curl_error($curl), curl_errno($curl) ); } [...] $response = new RawResponse( substr($returnTransfer, $headerSize), curl_getinfo($curl, CURLINFO_HTTP_CODE), $headers ); curl_close($curl); return $response; }}
namespace JMS\Payment\PaypalBundle\Client;
class Client { [...] public function request(Request $request) { [...] // perform the request if (false === $returnTransfer = curl_exec($curl)) { throw new CommunicationException( 'cURL Error: '.curl_error($curl), curl_errno($curl) ); } [...] $response = new RawResponse( substr($returnTransfer, $headerSize), curl_getinfo($curl, CURLINFO_HTTP_CODE), $headers ); curl_close($curl); return $response; }}
namespace JMS\Payment\PaypalBundle\Client;
class Client { [...] public function request(Request $request) { [...] // perform the request if (false === $returnTransfer = curl_exec($curl)) { throw new CommunicationException( 'cURL Error: '.curl_error($curl), curl_errno($curl) ); } [...] $response = new RawResponse( substr($returnTransfer, $headerSize), curl_getinfo($curl, CURLINFO_HTTP_CODE), $headers ); curl_close($curl); return $response; }}
namespace ACME\PaymentBundle\Tests\Stub;
use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function request(Request $request) { $response = new RawResponse( "TOKEN=BlaBlaBlaBla", 200, array( 'Date' => "Fri, 07 Sep 2012 15:21:00 GMT", 'Server' => "Apache", ) ); return $response; }}
namespace ACME\PaymentBundle\Tests\Stub;
use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function request(Request $request) { $response = new RawResponse( "TOKEN=BlaBlaBlaBla", 200, array( 'Date' => "Fri, 07 Sep 2012 15:21:00 GMT", 'Server' => "Apache", ) ); return $response; }}
services.xml
JMS\Payment\PaypalBundle\Client\Client
config_test.yml
parameters: payment.paypal.client.class: ACME\PaymentBundle\Tests\Stub\PaypalClientStub
namespace JMS\Payment\PaypalBundle\Client;
class Client { [...] public function getAuthenticateExpressCheckoutTokenUrl($token) { $host = $this->isDebug ? 'www.sandbox.paypal.com':'www.paypal.com';
return $host; }}
namespace ACME\PaymentBundle\Tests\Stub;use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function getAuthenticateExpressCheckoutTokenUrl($token) { return '/payment/paypalFakeController'; }}
namespace ACME\PaymentBundle\Tests\Stub;use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function request(Request $request) { if ($request->request->get('METHOD') == 'SetExpressCheckout') { $response = new RawResponse( "TOKEN=BlaBlaBla", ); } elseif ($request->request->get('METHOD') == 'GetExpressCheckoutDetails'){ $response = new RawResponse( "CHECKOUTSTATUS=PaymentCompleted&ACK=Success", ); } elseif ($request->request->get('METHOD') == 'DoExpressCheckoutPayment'){ $response = new RawResponse( "PAYMENTINFO_0_PAYMENTSTATUS=Completed", ); } return $response; }}
namespace ACME\PaymentBundle\Tests\Stub;use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function request(Request $request) { if ($request->request->get('METHOD') == 'SetExpressCheckout') { $response = new RawResponse( "TOKEN=BlaBlaBla", ); } elseif ($request->request->get('METHOD') == 'GetExpressCheckoutDetails'){ $response = new RawResponse( "CHECKOUTSTATUS=PaymentCompleted&ACK=Success", ); } elseif ($request->request->get('METHOD') == 'DoExpressCheckoutPayment'){ $response = new RawResponse( "PAYMENTINFO_0_PAYMENTSTATUS=Completed", ); } return $response; }}
namespace ACME\PaymentBundle\Tests\Stub;use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function request(Request $request) { if ($request->request->get('METHOD') == 'SetExpressCheckout') { $response = new RawResponse( "TOKEN=BlaBlaBla", ); } elseif ($request->request->get('METHOD') == 'GetExpressCheckoutDetails'){ $response = new RawResponse( "CHECKOUTSTATUS=PaymentCompleted&ACK=Success", ); } elseif ($request->request->get('METHOD') == 'DoExpressCheckoutPayment'){ $response = new RawResponse( "PAYMENTINFO_0_PAYMENTSTATUS=Completed", ); } return $response; }}
Something is missing
Control on the request
namespace ACME\PaymentBundle\Tests\Stub;use JMS\Payment\PaypalBundle\Client\Client;
class PaypalClientStub extends Client { public function request(Request $request) { if ($request != "OK STUFF") { throw new Exception ("Wrong Request for Paypal call"); } [...]
return $response; }}
What is outside?
External API
What is outside?
External API
OS services (time)
What is outside?
External API
OS services (time)
Systems that don't exist yet
What is outside?
External API
OS services (time)
Systems that don't exist yet
Systems that other people is working on
What is outside?
External API
OS services (time)
Systems that don't exist yet
Systems that other people is working on
Monsters from the inside(legacy code)
The date/time case
A user can see the next three appointments
The date/time case
A user can see the next three appointments
A user is shown an alert in home page if she has an appointment in the next 6 hours
The date/time case
A user can see the next three appointments
A user is shown an alert in home page if she has an appointment in the next 6 hours
A user can take an appointment for the next day, but if it is Friday the next eligible day will be Monday
namespace ACME\CoreBundle\Service;
class Time{ public static function getNow() { return new \DateTime(); }}
namespace Acme\CoreBundle\Test\Service;
class Time{ public static $referenceTime = '2012-05-01 12:00:00'; public static $time = null;
public static function getNow() { if (is_null(self::$time)) { return new \DateTime(self::$referenceTime); } else { return new \DateTime(self::$time); } }}
namespace Acme\CoreBundle\Test\Service;
class Time{ public static $referenceTime = '2012-05-01 12:00:00'; public static $time = null;
public static function getNow() { if (is_null(self::$time)) { return new \DateTime(self::$referenceTime); } else { return new \DateTime(self::$time); } }}
Use Acme\CoreBundle\Test\Service\Time;
public function load(ObjectManager $manager){ $appointmentToday = new Appointment(); $appointmentToday->setDateTime(new \DateTime(Time::$referenceTime)); [...]}
Inside the fixtures
Use Acme\CoreBundle\Test\Service\Time;
public function test_customerHome(){ Acme\CoreBundle\Test\Service\Time::$time = "2012-06-01";
[...]}
Inside the test
Different config states
$client = self::createClient(array('environment' => 'test_alternative'));
Thank You
@euxpomnerd2business.net