품목

PHPUnit 및 PEST를 사용하여 간단한 예제를 통해 Laravel에서 테스트를 수행하는 방법을 알아보세요.

모든 프로그래밍 언어에는 자동화된 테스트 또는 단위 테스트와 관련하여 두 가지 반대 의견이 있습니다.

  • 시간 낭비
  • 그것 없이는 할 수 없습니다

따라서 이 기사를 통해 우리는 특히 Laravel에서 자동화된 테스트를 시작하는 것이 얼마나 쉬운지를 보여줌으로써 전자를 설득하려고 노력할 것입니다.

먼저 "이유"에 대해 이야기한 다음 방법에 대한 몇 가지 예를 살펴보겠습니다.

자동화된 테스트가 필요한 이유

자동화된 테스트는 코드의 일부를 실행하고 오류를 보고합니다. 이것이 그들을 설명하는 가장 간단한 방법입니다. 앱에서 새로운 기능을 출시하면 개인 로봇 보조원이 직접 가서 새로운 기능을 테스트하는 동시에 새 코드가 기존 기능을 손상시키지 않는지 테스트한다고 상상해 보세요.

이것이 주요 장점입니다. 모든 기능을 자동으로 다시 테스트합니다. 이는 추가 작업처럼 보일 수 있지만 "로봇"에게 이를 지시하지 않으면 대신 수동으로 수행해야 합니다. 그렇죠? 

또는 사용자가 버그를 보고하기를 바라면서 작동 여부를 테스트하지 않고 새로운 기능을 출시할 수도 있습니다.

자동화된 테스트는 다음과 같은 몇 가지 이점을 제공합니다.

  • 수동 테스트 시간을 절약하세요.
  • 이를 통해 회귀를 방지하여 구현된 새 기능과 통합된 기능 모두에서 시간을 절약할 수 있습니다.
  • 모든 새로운 기능과 이미 구현된 모든 기능을 통해 이 이점을 배가할 수 있습니다.
  • 이전 세 가지 사항은 모든 새 버전에 적용됩니다.
  • ...

지난 몇 년 동안 작성된 코드나 테스트 방법을 모르는 팀의 새로운 개발자와 함께 XNUMX~XNUMX년 후에 애플리케이션을 상상해 보십시오. 

최초의 자동화된 테스트

첫 번째를 수행하려면 Laravel의 자동화된 테스트, 코드를 작성할 필요가 없습니다. 예, 당신이 읽은 것이 맞습니다. 설치 전 모든 것이 이미 구성 및 준비되어 있습니다.defi첫 번째 기본 예제를 포함하여 Laravel의 모든 것.

Laravel 프로젝트를 설치하고 첫 번째 테스트를 즉시 실행할 수 있습니다.

laravel new project
cd project
php artisan test

콘솔의 결과는 다음과 같습니다.

사전 내용을 살펴보면defiLaravel의 밤 /tests, 두 개의 파일이 있습니다.

테스트/기능/ExampleTest.php :

class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

여기서 무슨 일이 일어나고 있는지 이해하기 위해 구문을 알 필요는 없습니다. 홈 페이지를 로드하고 상태 코드가 있는지 확인하세요. HTTP è "200 OK".

메소드 이름이라고도 함 test_the_application_returns_a_successful_response() 밑줄 기호를 공백으로 바꾸면 테스트 결과를 볼 때 읽을 수 있는 텍스트가 됩니다.

테스트/단위/ExampleTest.php :

class ExampleTest extends TestCase
{
    public function test_that_true_is_true()
    {
        $this->assertTrue(true);
    }
}

좀 무의미해 보이는데, 이것이 사실인지 확인해 볼까요? 

단위 테스트에 대해서는 잠시 후에 구체적으로 이야기하겠습니다. 지금은 각 테스트에서 일반적으로 어떤 일이 발생하는지 이해해야 합니다.

  • 폴더의 각 테스트 파일 /tests TestCase를 확장하는 PHP 클래스입니다. PHP단위
  • 각 클래스 내에서 여러 메서드를 만들 수 있습니다. 일반적으로 상황을 테스트할 메서드는 하나입니다.
  • 각 방법에는 세 가지 조치가 있습니다. 상황 준비, 조치 실행, 결과가 예상대로인지 확인(확인)

구조적으로는 이것이 알아야 할 전부이며, 그 밖의 모든 것은 테스트하려는 정확한 항목에 따라 다릅니다.

빈 테스트 클래스를 생성하려면 다음 명령을 실행하면 됩니다.

php artisan make:test HomepageTest

파일이 생성됩니다 tests/Feature/HomepageTest.php:

class HomepageTest extends TestCase
{
    // Replace this method with your own ones
    public function test_example()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

이제 Laravel에서 테스트 코드가 실패하면 어떤 일이 발생하는지 살펴보겠습니다.

이제 테스트 어설션이 예상한 결과를 반환하지 않는 경우 어떤 일이 발생하는지 살펴보겠습니다.

예제 테스트를 다음과 같이 변경해 보겠습니다.

class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/non-existing-url');
 
        $response->assertStatus(200);
    }
}
 
 
class ExampleTest extends TestCase
{
    public function test_that_true_is_false()
    {
        $this->assertTrue(false);
    }
}

이제 명령을 실행하면 php artisan test 다시:

 FAIL  Tests\Unit\ExampleTest
⨯ that true is true
 
 FAIL  Tests\Feature\ExampleTest
⨯ the application returns a successful response
 
---
 
• Tests\Unit\ExampleTest > that true is true
Failed asserting that false is true.
 
at tests/Unit/ExampleTest.php:16
   12▕      * @return void
   13▕      */
   14▕     public function test_that_true_is_true()
   15▕     {
➜  16▕         $this->assertTrue(false);
   17▕     }
   18▕ }
   19▕
 
• Tests\Feature\ExampleTest > the application returns a successful response
Expected response status code [200] but received 404.
Failed asserting that 200 is identical to 404.
 
at tests/Feature/ExampleTest.php:19
   15▕     public function test_the_application_returns_a_successful_response()
   16▕     {
   17▕         $response = $this->get('/non-existing-url');
   18▕
➜  19▕         $response->assertStatus(200);
   20▕     }
   21▕ }
   22▕
 
 
Tests:  2 failed
Time:   0.11s

FAIL로 표시된 두 개의 실패한 테스트가 있으며 아래 설명과 실패한 테스트의 정확한 행을 가리키는 화살표가 있습니다. 오류는 이런 식으로 표시됩니다.

예: Laravel에서 등록 양식 코드 테스트

양식이 있고 다양한 사례를 테스트해야 한다고 가정합니다. 잘못된 데이터로 인해 실패하는지 확인하고 올바른 입력으로 성공하는지 확인하는 등의 작업을 수행합니다.

공식 스타터 키트 작성자: Laravel Breeze 나는 포함한다 그 안의 기능 테스트. 거기에서 몇 가지 예를 살펴보겠습니다.

tests/Feature/RegistrationTest.php

use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class RegistrationTest extends TestCase
{
    use RefreshDatabase;
 
    public function test_registration_screen_can_be_rendered()
    {
        $response = $this->get('/register');
 
        $response->assertStatus(200);
    }
 
    public function test_new_users_can_register()
    {
        $response = $this->post('/register', [
            'name' => 'Test User',
            'email' => 'test@example.com',
            'password' => 'password',
            'password_confirmation' => 'password',
        ]);
 
        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }
}

여기서는 하나의 클래스에 두 개의 테스트가 있습니다. 둘 다 등록 양식과 관련되어 있기 때문입니다. 하나는 양식이 올바르게 로드되었는지 확인하고 다른 하나는 제출이 제대로 작동하는지 확인합니다.

결과를 확인하는 두 가지 방법, 즉 두 가지 추가 주장에 대해 알아 보겠습니다. $this->assertAuthenticated()$response->assertRedirect(). 공식 문서에서 사용 가능한 모든 주장을 확인할 수 있습니다. PHP단위 e 라라벨 응답 . 이 주제에 대해 몇 가지 일반적인 주장이 발생한다는 점에 유의하세요. $this, 다른 사람들은 구체적인 사항을 확인합니다. $response경로 호출에서.

또 다른 중요한 점은 use RefreshDatabase;클래스 위에 획이 삽입된 문입니다. 이 예에서와 같이 테스트 작업이 데이터베이스에 영향을 미칠 수 있는 경우 필요합니다. 로깅은 데이터베이스에 새 항목을 추가합니다. users데이터베이스 테이블. 이를 위해서는 업데이트될 별도의 테스트 데이터베이스를 생성해야 합니다. php artisan migrate:fresh테스트가 실행될 때마다.

물리적으로 별도의 데이터베이스를 생성하거나 메모리 내 SQLite 데이터베이스를 사용하는 두 가지 옵션이 있습니다. 둘 다 파일에 구성되어 있습니다. phpunit.xml기본적으로 제공defi니타와 함께 Laravel. 특히 다음 부분이 필요합니다.

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_DRIVER" value="array"/>
    <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
    <!-- <env name="DB_DATABASE" value=":memory:"/> -->
    <env name="MAIL_MAILER" value="array"/>
    <env name="QUEUE_CONNECTION" value="sync"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="TELESCOPE_ENABLED" value="false"/>
</php>

참조 DB_CONNECTIONDB_DATABASE어떤 것에 댓글이 달렸나요? 서버에 SQLite가 있는 경우 가장 간단한 조치는 해당 줄의 주석 처리를 제거하는 것입니다. 그러면 테스트가 해당 메모리 내 데이터베이스에 대해 실행됩니다.

이 테스트에서는 사용자가 성공적으로 인증되어 올바른 홈페이지로 리디렉션되었다고 말하지만 데이터베이스의 실제 데이터도 테스트할 수 있습니다.

이 코드 외에도:

$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);

우리는 또한 사용할 수 있습니다 데이터베이스 테스트 어설션 다음과 같이 하세요:

$this->assertDatabaseCount('users', 1);
 
// Or...
$this->assertDatabaseHas('users', [
    'email' => 'test@example.com',
]);

로그인 페이지의 예

이제 Laravel Breeze를 사용한 로그인 페이지의 또 다른 예를 살펴보겠습니다.

tests/Feature/AuthenticationTest.php:

class AuthenticationTest extends TestCase
{
    use RefreshDatabase;
 
    public function test_login_screen_can_be_rendered()
    {
        $response = $this->get('/login');
 
        $response->assertStatus(200);
    }
 
    public function test_users_can_authenticate_using_the_login_screen()
    {
        $user = User::factory()->create();
 
        $response = $this->post('/login', [
            'email' => $user->email,
            'password' => 'password',
        ]);
 
        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }
 
    public function test_users_can_not_authenticate_with_invalid_password()
    {
        $user = User::factory()->create();
 
        $this->post('/login', [
            'email' => $user->email,
            'password' => 'wrong-password',
        ]);
 
        $this->assertGuest();
    }
}

로그인 양식에 관한 것입니다. 논리는 등록과 비슷합니다. 그렇죠? 하지만 두 가지 방법이 아닌 세 가지 방법이 있으므로 이는 좋은 시나리오와 나쁜 시나리오를 모두 테스트하는 예입니다. 따라서 일반적인 논리는 일이 잘 될 때와 실패할 때 두 가지 경우를 모두 테스트해야 한다는 것입니다.

혁신 뉴스레터
혁신에 관한 가장 중요한 뉴스를 놓치지 마세요. 이메일로 받으려면 가입하세요.

또한 이 테스트에서 볼 수 있는 것은 데이터베이스 팩토리 : Laravel은 가짜 사용자를 생성합니다( 다시 한 번 업데이트된 테스트 데이터베이스에서 ) 그런 다음 올바른 또는 잘못된 자격 증명을 사용하여 로그인을 시도합니다.

다시 한번 Laravel은 팩토리 프리를 생성합니다.defi니타가 잘못된 데이터를 갖고 있어요 User모델, 상자 외부.

database/factories/UserFactory.php:

class UserFactory extends Factory
{
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

라라벨 자체적으로 준비되어 있는 것들이 얼마나 많은지, 테스트를 시작하기 쉽겠죠?

그래서 우리가 실행하면 php artisan testLaravel Breeze를 설치한 후 다음과 같은 내용이 표시됩니다.

 PASS  Tests\Unit\ExampleTest
✓ that true is true
 
 PASS  Tests\Feature\Auth\AuthenticationTest
✓ login screen can be rendered
✓ users can authenticate using the login screen
✓ users can not authenticate with invalid password
 
 PASS  Tests\Feature\Auth\EmailVerificationTest
✓ email verification screen can be rendered
✓ email can be verified
✓ email is not verified with invalid hash
 
 PASS  Tests\Feature\Auth\PasswordConfirmationTest
✓ confirm password screen can be rendered
✓ password can be confirmed
✓ password is not confirmed with invalid password
 
 PASS  Tests\Feature\Auth\PasswordResetTest
✓ reset password link screen can be rendered
✓ reset password link can be requested
✓ reset password screen can be rendered
✓ password can be reset with valid token
 
 PASS  Tests\Feature\Auth\RegistrationTest
✓ registration screen can be rendered
✓ new users can register
 
 PASS  Tests\Feature\ExampleTest
✓ the application returns a successful response
 
Tests:  17 passed
Time:   0.61s

단위 테스트 및 기타 기능 테스트와 비교

하위 폴더를 확인했습니다. tests/Feature e tests/Unit ?. 

그들 사이의 차이점은 무엇입니까? 

전 세계적으로 Laravel/PHP 생태계 외부에는 여러 유형의 자동화된 테스트가 있습니다. 다음과 같은 용어를 찾을 수 있습니다.

  • 단위 테스트
  • 기능 테스트
  • 통합 테스트
  • 기능 테스트
  • 엔드 투 엔드 테스트
  • 승인 테스트
  • 연기 테스트
  • 등.

복잡하게 들리며 이러한 유형의 테스트 간의 실제 차이점이 모호해지는 경우도 있습니다. 이것이 바로 Laravel이 이러한 모든 혼란스러운 용어를 단순화하고 이를 단위/기능이라는 두 가지로 그룹화한 이유입니다.

간단히 말해서 기능 테스트는 애플리케이션의 실제 기능을 실행하려고 시도합니다. URL을 가져오고, API를 호출하고, 양식 작성과 같은 정확한 동작을 모방합니다. 기능 테스트는 일반적으로 프로젝트 사용자가 실제 생활에서 수동으로 수행하는 것과 동일하거나 유사한 작업을 수행합니다.

단위 테스트에는 두 가지 의미가 있습니다. 일반적으로 자동화된 테스트를 "단위 테스트"라고 하며 전체 프로세스를 "단위 테스트"라고 부를 수 있습니다. 그러나 기능 대 단위의 맥락에서 이 프로세스는 특정 비공개 코드 단위를 별도로 테스트하는 것입니다. 예를 들어 매개변수를 사용하여 총 주문 가격과 같은 항목을 계산하는 메서드가 있는 Laravel 클래스가 있습니다. 따라서 단위 테스트에서는 해당 메서드(코드 단위)에서 다른 매개 변수를 사용하여 올바른 결과가 반환되는지 여부를 명시합니다.

단위 테스트를 생성하려면 플래그를 추가해야 합니다.

php artisan make:test OrderPriceTest --unit

생성된 코드는 사전 단위 테스트와 동일합니다.defi라라벨 시스템:

class OrderPriceTest extends TestCase
{
    public function test_example()
    {
        $this->assertTrue(true);
    }
}

보시다시피 존재하지 않습니다 RefreshDatabase, 그리고 이것은 다음 중 하나입니다 defi가장 일반적인 단위 테스트 정의: 데이터베이스를 건드리지 않고 실행 중인 애플리케이션에서 격리된 "블랙 박스"로 작동합니다.

앞서 언급한 예를 모방하여 서비스 클래스가 있다고 가정해 보겠습니다. OrderPrice.

app/Services/OrderPriceService.php:

class OrderPriceService
{
    public function calculatePrice($productId, $quantity, $tax = 0.0)
    {
        // Some kind of calculation logic
    }
}

그러면 단위 테스트는 다음과 같을 수 있습니다.

class OrderPriceTest extends TestCase
{
    public function test_single_product_no_taxes()
    {
        $product = Product::factory()->create(); // generate a fake product
        $price = (new OrderPriceService())->calculatePrice($product->id, 1);
        $this->assertEquals(1, $price);
    }
 
    public function test_single_product_with_taxes()
    {
        $price = (new OrderPriceService())->calculatePrice($product->id, 1, 20);
        $this->assertEquals(1.2, $price);
    }
 
    // More cases with more parameters
}

Laravel 프로젝트에 대한 개인적인 경험에 따르면 대부분의 테스트는 단위 테스트가 아닌 기능 테스트입니다. 먼저, 실제 사람들이 사용하는 방식으로 애플리케이션이 작동하는지 테스트해야 합니다.

다음으로 특별한 계산이나 논리가 있는 경우 다음을 수행할 수 있습니다. definire를 하나의 단위로 사용하고 매개변수를 사용하여 특별히 해당 단위 테스트를 만들 수 있습니다.

때로는 테스트를 작성하려면 코드 자체를 수정하고 리팩토링하여 코드를 더 "테스트 가능"하게 만들어야 합니다. 즉, 유닛을 특수 클래스나 메서드로 분리해야 합니다.

언제/어떻게 테스트를 수행합니까?

이것의 실제 용도는 무엇입니까? php artisan test, 언제 실행해야 합니까?

비즈니스 워크플로에 따라 다양한 접근 방식이 있지만 일반적으로 최종 코드 변경 사항을 저장소에 푸시하기 전에 모든 테스트가 "녹색"(즉, 오류 없음)인지 확인해야 합니다.

그런 다음 로컬에서 작업을 수행하고 작업이 완료되었다고 생각되면 몇 가지 테스트를 실행하여 손상된 부분이 없는지 확인합니다. 여러분의 코드는 논리에 버그를 일으킬 수 있을 뿐만 아니라 오래 전에 작성된 다른 사람의 코드에서 의도치 않게 다른 동작을 중단시킬 수도 있다는 점을 기억하십시오.

한 단계 더 발전하면 자동화도 가능하다. 많은 것들. 다양한 CI/CD 도구를 사용하면 누군가가 특정 Git 분기에 변경 사항을 푸시할 때마다 또는 코드를 프로덕션 분기에 병합하기 전에 실행할 테스트를 지정할 수 있습니다. 가장 간단한 작업 흐름은 Github Actions를 사용하는 것입니다. 별도의 영상 그것을 증명하는 것입니다.

무엇을 테스트해야 합니까?

소위 "테스트 적용 범위"가 얼마나 커야 하는지에 대해 다양한 의견이 있습니다. 모든 페이지에서 가능한 모든 작업과 사례를 시도하거나 가장 중요한 부분으로 작업을 제한합니다.

사실 자동화된 테스트가 실제 이점을 제공하는 것보다 시간이 더 많이 걸린다고 비난하는 사람들의 의견에 저는 동의합니다. 모든 단일 세부 사항에 대한 테스트를 작성하면 이런 일이 발생할 수 있습니다. 즉, 프로젝트에 필요할 수 있습니다. 주요 질문은 "잠재적인 오류의 대가는 얼마입니까?"입니다.

즉, "이 코드가 실패하면 어떻게 될까요?"라는 질문을 던져 테스트 노력의 우선순위를 정해야 합니다. 결제 시스템에 버그가 있으면 비즈니스에 직접적인 영향을 미칩니다. 따라서 역할/권한의 기능이 손상되면 이는 큰 보안 문제입니다.

나는 Matt Stauffer가 컨퍼런스에서 다음과 같이 말한 것을 좋아합니다. "실패할 경우 직장에서 해고될 수 있는 것들을 먼저 테스트해야 합니다." 물론 그것은 과장된 표현이지만, 중요한 것을 먼저 시도해 보십시오. 그리고 시간이 있으면 다른 기능도 살펴보세요.

PEST: PHPUnit의 새로운 대안

위의 모든 예는 Laravel 사전 테스트 도구를 기반으로 합니다.defi밤: PHP단위 . 그러나 수년에 걸쳐 생태계에 다른 도구가 등장했으며 가장 최근에 인기 있는 도구 중 하나는 다음과 같습니다. 해충 . 공식 Laravel 직원이 작성함 누노 마두로 는 구문을 단순화하여 테스트용 코드 작성 속도를 더욱 빠르게 만드는 것을 목표로 합니다.

후드 아래에서 실행됩니다. su PHPUnit은 추가 레이어로서 사전 반복되는 일부 부분을 최소화하려고 합니다.defiPHPUnit 코드 중 하나입니다.

예를 살펴보겠습니다. 사전 기능 테스트 수업을 기억하세요defiLaravel에 포함되어 있나요? 나는 당신에게 상기시켜 드리겠습니다:

namespace Tests\Feature;
 
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    public function test_the_application_returns_a_successful_response()
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

동일한 테스트가 PEST와 어떻게 다른지 아시나요?

test('the application returns a successful response')->get('/')->assertStatus(200);

예, 코드 한 줄이면 끝입니다. 따라서 PEST의 목표는 다음과 같은 오버헤드를 제거하는 것입니다.

  • 모든 것에 대한 클래스와 메소드 생성
  • 테스트 케이스 확장;
  • 별도의 줄에 작업을 추가하면 PEST에서는 작업을 함께 연결할 수 있습니다.

Laravel에서 PEST 테스트를 생성하려면 추가 플래그를 지정해야 합니다:

php artisan make:test HomepageTest --pest

이 글을 쓰는 시점에서 PEST는 Laravel 개발자들 사이에서 꽤 인기가 있지만, 이 추가 도구를 사용하고 해당 구문과 PHPUnit 참고 사항을 배울지는 개인 취향입니다.

BlogInnovazione.it

혁신 뉴스레터
혁신에 관한 가장 중요한 뉴스를 놓치지 마세요. 이메일로 받으려면 가입하세요.

최근 기사

미래가 여기에 있습니다: 해운 산업이 글로벌 경제를 어떻게 혁신하고 있습니까?

해군 부문은 150억 시장을 향해 항해해온 진정한 글로벌 경제강국입니다.

1 월 2024

출판사와 OpenAI, 인공지능이 처리하는 정보의 흐름을 규제하기 위한 계약 체결

지난 월요일, Financial Times는 OpenAI와의 계약을 발표했습니다. FT는 세계적 수준의 저널리즘에 라이선스를 부여합니다…

4월 30 2024

온라인 결제: 스트리밍 서비스를 통해 영원히 결제하는 방법은 다음과 같습니다.

수백만 명의 사람들이 스트리밍 서비스 비용을 지불하고 월간 구독료를 지불합니다. 당신은…

4월 29 2024

Veeam은 보호부터 대응, 복구까지 랜섬웨어에 대한 가장 포괄적인 지원을 제공합니다.

Coveware by Veeam은 계속해서 사이버 강탈 사건 대응 서비스를 제공할 것입니다. Coveware는 법의학 및 교정 기능을 제공할 것입니다…

4월 23 2024