Laravel - PHPUnit многошаговое тестирование - PullRequest
0 голосов
/ 11 января 2019

Я новичок в мире юнит-тестирования. Я хочу, чтобы мои тесты были как можно более четкими, чистыми и абстрагированными. У меня есть следующий класс -

class PasswordResetTest extends GraphQLTest
{

private static $user;
private $authEndpoint = '/graphql/auth';

protected function setUp()
{
    parent::setUp();

    if (!self::$user instanceof User) {
        self::$user = factory(User::class)->create(
            ['password' => Hash::make('password')]
        );
    }
}

/**
 * Check our default password was set successfully
 *
 * @test
 */
public function assertDefaultPassword()
{
    // get our user
    $user = User::where('email', self::$user->email)->get();

    // check our password is 'password'
    $this->assertTrue(
        Hash::check('password', self::$user->fresh()->password),
        'Unexpected password'
    );
}

/**
 * Perform a password reset via GraphQL
 *
 * @test
 */
public function requestPasswordResetEmail()
{
    // setup our mail faker
    Mail::fake();

    // make sure nothing has been sent
    Mail::assertNothingSent();

    // set our endpoint
    $this->setGraphQLEndpoint($this->authEndpoint);
    $mutation = 'mutation forgotPassword ($email: String) {
        forgotPassword (email: $email)
    }';

    // make our request
    $result = $this->graphQLRequest($mutation, ['email' => self::$user->email]);

    // assert our response
    $result->assertJson(['data' => ['forgotPassword' => true]]);

    // check our reset was sent...
    Mail::assertSent(
        PasswordResetMail::class,
        function (PasswordResetMail $mail) use (&$reset) {
            $reset = $mail->reset;
            return $mail->hasTo(self::$user->email);
        }
    );

    return $reset;
}

/**
 * If our email was sent, now perform our reset...
 *
 * @depends requestPasswordResetEmail
 * @test
 */
public function performPasswordReset(PasswordReset $reset)
{

    // set our endpoint and create mutation
    $this->setGraphQLEndpoint($this->authEndpoint);
    $mutation = 'mutation resetPassword ($reset: inputResetPassword!) {
        resetPassword (reset: $reset)                     
    }';

    $result = $this->graphQLRequest($mutation, [
        'reset' => [
            'token' => $reset->token,
            'password' => 'newPassword',
            'password_confirmation' => 'newPassword',
        ]
    ]);

    $result->assertGraphQLNoErrors();
    $result->assertJson(['data' => ['resetPassword' => true]]);
}

Итак, я хочу запустить свои тесты несколькими частями -

  • Проверьте, действительно ли пароль был установлен против пользователя
  • Запрос сброса пароля и подтверждение отправки электронного письма
  • Выполните сброс пароля и подтвердите, что наш пароль обновлен

Я мог бы запустить все эти тесты в одном методе, но я бы предпочел разделить их на отдельные тесты для удобства чтения и проверки, но я столкнулся с парой проблем -

  • setUp() метод выполняется для каждого теста, а не для целого класса тестов, поэтому в каждом тесте у меня новый пользователь, а не то, что я хочу
  • Если я использую DatabaseTransactions - это то, что я в идеале хотел бы использовать, это также сбрасывает базу данных каждый тест, поэтому последующие тесты не пройдут

Есть ли способ добиться того, что я пытаюсь сделать, или мне нужно написать это как один большой тест?

Спасибо!

1 Ответ

0 голосов
/ 11 января 2019

Один из возможных способов сделать это - использовать @depends phpdoc

.
class PasswordResetTest extends GraphQLTest
{

private static $user;
private $authEndpoint = '/graphql/auth';

/**
 * @test
 */
public function assertDefaultPassword()
{

    // create our user
    self::$user = factory(User::class)->create(
        ['password' => Hash::make('oldPassword')]
    );

    // check we exist on the database
    $this->assertDatabaseHas('users', ['email' => self::$user->email]);

    // check our password is 'password'
    $this->assertTrue(
        Hash::check('oldPassword', self::$user->password),
        'Unexpected password'
    );
}

/**
 * Perform a password reset via GraphQL
 *
 * @depends assertDefaultPassword
 * @test
 *
 * @param User $user
 *
 * @return mixed
 */
public function requestPasswordResetEmail()
{
    Mail::fake();

    // make sure nothing has been sent
    Mail::assertNothingSent();

    // set our endpoint
    $this->setGraphQLEndpoint($this->authEndpoint);
    $mutation = 'mutation forgotPassword ($email: String) {
        forgotPassword (email: $email)
    }';

    // make our request
    $result = $this->graphQLRequest($mutation, ['email' => self::$user->email]);

    // assert our response
    $result->assertJson(['data' => ['forgotPassword' => true]]);

    // check our reset was sent...
    Mail::assertSent(
        PasswordResetMail::class,
        function (PasswordResetMail $mail) use (&$reset) {
            $reset = $mail->reset;
            return $mail->hasTo(self::$user->email);
        }
    );

    return $reset;
}

/**
 * If our email was sent, now perform our reset...
 *
 * @depends requestPasswordResetEmail
 * @test
 */
public function performPasswordReset(PasswordReset $reset)
{

    // set our endpoint and create mutation
    $this->setGraphQLEndpoint($this->authEndpoint);
    $mutation = 'mutation resetPassword ($reset: inputResetPassword!) {
        resetPassword (reset: $reset)                     
    }';

    // make request to our reset
    $result = $this->graphQLRequest(
        $mutation, [
            'reset' => [
                'token' => $reset->token,
                'password' => 'newPassword',
                'password_confirmation' => 'newPassword',
            ]
        ]
    );

    $result->assertGraphQLNoErrors();
    $result->assertJson(['data' => ['resetPassword' => true]]);
}

/**
 * After we have performed all of our tests, delete our user...
 */
public static function tearDownAfterClass()
{
    self::$user->forceDelete();
    parent::tearDownAfterClass();
}

}

Таким образом, я могу определить своего пользователя в первом тесте, последующие тесты имеют @depends phpdoc, который ссылается на предыдущие тесты, что позволяет мне настроить пользователя в первом запросе и получить доступ к пользователю в последующих запросах.

Затем я использовал метод tearDownAfterClass, чтобы удалить созданного пользователя из базы данных. Я хотел бы услышать решения других людей, хотя!

...