Testy integracyjne

Post on 14-Apr-2017

225 views 0 download

Transcript of Testy integracyjne

Testy integracyjne

Łukasz Zakrzewski
Automatyzujmy swoją prace,Nie bądzmy programistami F5,Dbajmy o jakość,Testy integracyjne to inwestycja, która się zwraca.

Kilka słów o sobie

Łukasz Zakrzewski

- http://lzakrzewski.com

- http://github.com/lzakrzewski

- @lzakrzewski_php

- http://clearcode.cc/

CEL PREZENTACJI

Łukasz Zakrzewski
Co mnie zmotywowało

Piramida testów

Dlaczego testy integracyjne są istotne?

Manualny test integracyjny - Given

Łukasz Zakrzewski
Byłem nieświadomy tego że stosuję testy integracyjne

Manualny test integracyjny - When

Manualny test integracyjny - Then

Testy integracyjne - automatyzacja

KORZYŚCI

Łukasz Zakrzewski
Oszczędność czasu,Poprawa jakości,Dokumentacja kodu,Obniżenie prawdopodobieństwa regresji.
Łukasz Zakrzewski
Czyli to co nam daje automatyzacja testów integracyjnych

PRZYKŁADY

Integracja z frameworkiem - kontroler

//...

class UserController extends Controller{ /** * @Rest\Post("/users", name="register_user", defaults={"_format" : "json"}) */ public function registerUserAction(Request $request) { $this->get('examples.use_case.register_user') ->register( $request->get('email'), $request->get('password') );

return new JsonResponse('', 201); }}

Łukasz Zakrzewski
Integracja z kodem ktory nie jest nasz
Łukasz Zakrzewski
Pierwszym przypadkiem

Integracja z frameworkiem - test kontrolera

//...

class UserControllerTest extends TestCase{ /** @test */ public function user_can_be_registered() { $userData = ['email' => 'user@example.com', 'password' => 'testing1'];

$this->sendJsonRequest('POST', '/users', $userData);

$this->assertResponseStatus(201); }}

Integracja z frameworkiem - konfiguracja

services: examples.subscriber.admin_notifier: class: Examples\Subscriber\AdminNotifier arguments: - "@examples.mailer" tags: 0: name: event_subscriber subscribes_to: Examples\Model\UserWasRegistered method: notify

Integracja z frameworkiem - test konfiguracji

//...

class AdminNotifierTest extends TestCase{ /** @test */ public function it_notifies_admin_when_user_was_registered() { $this->handle( new UserWasRegistered(1, 'user1@example.com', new \DateTime('2017-01-01')) );

$this->assertEquals(1, $this->getSentNotificationsCount()); }}

Integracja z bazą danych - repozytorium

//...

class ORMUserRepository implements UserRepository{ private $entityManager;

public function __construct(EntityManager $entityManager) { $this->entityManager = $entityManager; }

public function add(User $user) { $this->entityManager->persist($user); $this->entityManager->flush(); }

public function get($id) { return $this ->entityManager ->find(User::class, $id); }}

Integracja z bazą danych - test repozytorium

//...

class ORMUserRepositoryTest extends TestCase{ /** @test */ public function it_adds_user() { $this->givenDatabaseIsClear(); $user = new User(1, 'user@example.com', 'testing1');

$this->repository->add($user);

$this->assertThatUserWithIdWasCreated(1); }

/** @test */ public function it_gets_user_by_id() { $this->givenDatabaseIsClear(); $this->repository->add( new User(1, 'user@example.com', 'testing1') );

$user = $this->repository->get(1);

$this->assertInstanceOf(User::class, $user); $this->assertEquals(1, $user->getId()); $this->assertEquals('user@example.com', $user->getEmail()); }}

Integracja z zewnętrznym API - FacebookAPI

//...

class FacebookApiAdapter implements FacebookApi{ const GRAPH_API_ME_URL = 'https://graph.facebook.com/v2.5/me';

private $client;

public function __construct(ClientInterface $client) { $this->client = $client; }

public function me($accessToken) { $request = $this ->client ->createRequest('GET', self::GRAPH_API_ME_URL.'?access_token='.$accessToken);

$response = $this ->client ->send($request);

return json_decode($response->getBody()->getContents(), true); }}

Integracja z zewnętrznym API - test

//...

class FacebookApiAdapterTest extends TestCase{ /** @test */ public function it_can_retrieve_user_node_successfully() { $userNode = $this->adapter->me($this->accessToken());

$this->assertEquals( [ 'id' => '10203138100203984', 'name' => 'DolorAmit LoremIpsum', ], $userNode ); }}

PRAKTYKA

Test driven development - cz. 1

//...

class UserControllerTest extends TestCase{ /** @test */ public function user_can_be_registered() { $userData = ['email' => 'user@example.com', 'password' => 'testing1'];

$this->sendJsonRequest('POST', '/users', $userData);

$this->assertResponseStatus(201); }}

Łukasz Zakrzewski
artykuly mowia o tym ze testy wydluzaja czas developmentu ja sie z tym nie zgadzam, bo
Łukasz Zakrzewski
po tescie kontrolera moge przejsc do implementacji usecasu w ktorym rejestrowany jest user a potem implementacji repozytorium w ktorym user jest dodawany
Łukasz Zakrzewski
nawiązanie do tego co wspomnialem o przyspieszeniu developmentu
Łukasz Zakrzewski
Przyspieszenie developmentu

Test driven development - cz. 2

Test driven development - cz. 3

//...

class UserController extends Controller{ /** * @Rest\Post("/users", name="register_user", defaults={"_format" : "json"}) */ public function registerUserAction(Request $request) { return new JsonResponse('', 201); }}

Test driven development - cz. 4

Test driven development - cz. 5

//...

class UserController extends Controller{ /** * @Rest\Post("/users", name="register_user", defaults={"_format" : "json"}) */ public function registerUserAction(Request $request) { // Your stuff there ...

return new JsonResponse('', 201); }}

Feedback

Łukasz Zakrzewski
refactoring
Łukasz Zakrzewski
upgrejd

PERFORMANCE

Profilowanie

Edge-cases

Łukasz Zakrzewski
validacja email

Set-up bazy danych

SQLite - konfiguracja

doctrine: dbal: driver: pdo_sqlite path: "%kernel.cache_dir%/test.db"

Transakcje

//...

class RepositoryTest extends TestCase{ /** @test */ public function reverting_transaction() { $this->givenDatabaseIsClear(); $this->getEntityManager()->beginTransaction();

$this->add(new Teapot('brand-new-teapot', 10.0)); $this->add(new Phone('amazing-phone', 400.0));

$items = ItemRepository::create($this->getEntityManager()) ->paginate(1, 2);

$this->assertCount(2, $items);

$this->getEntityManager()->rollback(); }}

Fake, stub - cz. 1

//...

class FacebookApiAdapter implements FacebookApi{ const GRAPH_API_ME_URL = 'https://graph.facebook.com/v2.5/me';

/** @var ClientInterface */ private $client;

public function __construct(ClientInterface $client) { $this->client = $client; }

/** {@inheritdoc} */ public function me($accessToken) { $request = $this ->client ->createRequest('GET', self::GRAPH_API_ME_URL.'?access_token='.$accessToken);

$response = $this ->client ->send($request);

return json_decode($response->getBody()->getContents(), true); }}

Fake, stub - cz. 2

//...

interface FacebookApi{ /** * Returns a user node as array. * * @param string $accessToken * * @return array */ public function me($accessToken);}

Fake, stub - cz. 3

//...

class FakeFacebookApiAdapter implements FacebookApi{ /** {@inheritdoc} */ public function me($accessToken) { return [ 'id' => '10203138100203984', 'name' => 'DolorAmit LoremIpsum', ]; }}

PODSUMOWANIE

Łukasz Zakrzewski
2 główne zalety
Łukasz Zakrzewski
przyklady byly dosc podstawowe, mialo to na celu przedstawienie idei
Łukasz Zakrzewski
szybkoscjakosczachecenieniewychodzenie z przegladarki

PYTANIA ?

Linki:

https://github.com/lzakrzewski/DoctrineDatabaseBackup

http://lzakrzewski.com/2016/02/tricks-to-speed-up-database-tests/

https://github.com/lzakrzewski/tests-with-database-examples

https://blackfire.io

http://symfony.com/doc/current/book/testing.html#functional-tests