Laravel-PHPUnit多步测试

时间:2019-01-11 11:10:54

标签: laravel phpunit laravel-5.7 phpunit-testing

我是单元测试领域的新手。我希望我的测试尽可能清晰,干净和抽象。我有以下课程-

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 :(得分:0)

一种可行的方法是使用@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方法从数据库中删除了创建的用户。我还是很想听听其他人的解决方案!