Symfony a testy

0

Witam

Piszę sobie w Symfony, mam już spory kawałek mojej aplikacji i w końcu wypadałoby też napisać testy. I tutaj pytanie jak to dobrze robić. Korzystam z PHPUnit i problem jaki spotkałem na samym początku to logowanie, którego wymaga moja aplikacja. W dokumentacji znalazłem jakiś "trick": http://symfony.com/doc/current/testing/http_authentication.html ale ten mi nie działa. Działa sposób z dołu, z tym że to nie może być u mnie tak po prostu podany login, ale muszę przy użyciu Doctrine pobrać tego usera z bazy. Gdy daję sam login wysypuje się gdzieś przy odwołaniu do app.user w Twigu, że nie ma tam obiektu usera, jest null. Z kolei gdy zrobię nowy obiekt usera to sypie się, że nie ma on id, więc też są jakieś problemy. Test jak rozumiem powinien być samodzielny, więc wychodzi na to, że przed jego wykonaniem muszę zrobić usera, zapisać go do bazy, zasymulować logowanie, wykonać test i na koniec usunąć usera z bazy? Wydaje się dużo, czy na pewno tak powinno to wyglądać?

W ogóle jak testować aplikację która operuje na bazie danych? Tworzyć i usuwać wszystko w danym teście, może mockować EntityManagera/repozytoria a może zrobić transakcję na początku testu i po zakończeniu ją wycofać co nie spowoduje zmian na bazie? Mam wrażenie, że znam ogólne założenia na temat testów, ale bardzo gubię się gdy trzeba zrobić coś konkretnego - chciałbym zrobić to dobrze, a nie do końca wiem jak :/

Z góry dziękuję za pomoc!

0

To jest trik wykorzystywany przy standardowym sposobie uwierzytelnienia a jak masz uwierzytelnienie przez token, to musisz inaczej to zrobić. Musisz wygenerować token i zapisać go w sesji.
Daje Ci gotowca:

	public function login(string $user = 'admin', string $password = 'qwerty123', array $role = ['ROLE_ADMIN'])
	{
		$session = $this->client->getContainer()->get('session');
		$firewallContext = 'main';
		$token = new UsernamePasswordToken($user, $password, $firewallContext, $role);
		$session->set('_security_' . $firewallContext, serialize($token));
		$session->save();
		$cookie = new Cookie($session->getName(), $session->getId());
		$this->client->getCookieJar()->set($cookie);
	}

0

@Paweł Antyporowicz: tak jak napisałem:

Działa sposób z dołu, z tym że to nie może być u mnie tak po prostu podany login, ale muszę przy użyciu Doctrine pobrać tego usera z bazy. Gdy daję sam login wysypuje się gdzieś przy odwołaniu do app.user w Twigu, że nie ma tam obiektu usera, jest null.

Więc niestety nic mi ten gotowiec nie daje.

0

Pokaż kod pliku security.yml i jak masz zrealizowane logowanie? Jeżeli tak: https://symfony.com/doc/current/security/form_login_setup.html to ten sposób co Ci wysyłałem wyżej powinien Ci działać. Klasa

UsernamePasswordToken

automatycznie sprawdza czy dany użytkownik jest bazie danych, jeżeli jest, to dopiero dostajesz uwierzytelnienie.

0

@Paweł Antyporowicz:

Mój security.yaml

security:
    encoders:
        App\Entity\User: bcrypt

    role_hierarchy:
        ROLE_ADMIN: ROLE_USER

    providers:
        db:
            entity:
                class: App\Entity\User

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            form_login:
                login_path: /login
                check_path: /login
            logout:
                path: /logout

    access_control:
        - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_USER }

W teście mam:

$token = new UsernamePasswordToken('test', 'test', $firewallContext, ['ROLE_USER']);

Dostaję błąd:

TypeError: Argument 1 passed to App\User\UserExtension::getData() must be an instance of App\Entity\User, null given, called in ...

Funkcja na którą błąd wskazuje:

public function getData(User $user): string
    {
        ....
    }

Wywoływana jest z widoku (bo to funkcja do Twiga): {{ user_data(app.user)) }}

Czyli w skrócie przekazuję do rozszerzenia encje usera, a okazuje się że tam jest null. Czyli coś jest nie tak z tym logowaniem, bo niby coś robi, ale użytkownik zalogowany jest jakoś źle.

Gdy zmienię w teście tak:

$user = $client->getContainer()->get('doctrine')->getRepository('App:User')->find(1);
$token = new UsernamePasswordToken($user, null, $firewallContext, ['ROLE_ADMIN']);

To wszystko działa. Tylko nie wiem czy tak się powinno robić, wydaje mi się jakoś dużo zabawy, aby tylko się zalogować a co dopiero dalej... Poza tym czy tego nie zrobię tak, czy tak jak ty pokazałeś, to i tak ten user musi być w bazie? Więc kiedy powinienem go tam dodać, w metodzie setUp dla testu? I za każdym razem dodać usera i po wykonaniu testu go usuwać? I tak samo z innymi danymi których będę używał w testach?

1 użytkowników online, w tym zalogowanych: 0, gości: 1