테스트
프로바이더 테스트
서비스 컨테이너에 바인딩된 서비스를 테스트할 때 사용할 수 있는 몇 가지 방법을 설명하겠습니다. 이를 통해 바인딩된 서비스의 동작을 검증하고, 의존성을 주입받는 클래스의 테스트를 용이하게 할 수 있습니다.
1. 모의 객체(Mock) 사용
라라벨에서는 PHPUnit과 Mockery를 사용하여 모의 객체를 생성하고 테스트할 수 있습니다. 모의 객체를 통해 실제 구현체 대신 가짜 객체를 주입하여 테스트를 수행합니다.
예시 코드
먼저, 테스트할 인터페이스와 서비스를 정의합니다.
namespace App\Services;
interface GreetingServiceInterface
{
public function greet($name);
}
class GreetingService implements GreetingServiceInterface
{
public function greet($name)
{
return "Hello, $name!";
}
}
그 다음, 컨트롤러를 정의합니다.
namespace App\Http\Controllers;
use App\Services\GreetingServiceInterface;
class GreetingController extends Controller
{
protected $greetingService;
public function __construct(GreetingServiceInterface $greetingService)
{
$this->greetingService = $greetingService;
}
public function greet($name)
{
return $this->greetingService->greet($name);
}
}
테스트 클래스를 생성하고 모의 객체를 사용하여 테스트합니다.
use Tests\TestCase;
use App\Services\GreetingServiceInterface;
use App\Http\Controllers\GreetingController;
use Mockery;
class GreetingControllerTest extends TestCase
{
public function testGreet()
{
// GreetingServiceInterface의 모의 객체 생성
$mockService = Mockery::mock(GreetingServiceInterface::class);
// greet 메서드가 "Hello, John!"을 반환하도록 설정
$mockService->shouldReceive('greet')
->with('John')
->andReturn('Hello, John!');
// 컨트롤러에 모의 객체 주입
$controller = new GreetingController($mockService);
// 메서드 호출 및 결과 검증
$response = $controller->greet('John');
$this->assertEquals('Hello, John!', $response);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
}
2. 서비스 컨테이너를 통한 테스트
라라벨의 서비스 컨테이너를 이용하여 직접 인스턴스를 주입하는 방식으로 테스트할 수 있습니다.
예시 코드
먼저, 서비스를 서비스 컨테이너에 바인딩합니다.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\GreetingServiceInterface;
use App\Services\GreetingService;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(GreetingServiceInterface::class, GreetingService::class);
}
public function boot()
{
//
}
}
그 다음, 테스트 클래스를 작성합니다.
use Tests\TestCase;
use App\Services\GreetingServiceInterface;
class GreetingServiceTest extends TestCase
{
public function testGreet()
{
// 서비스 컨테이너에서 인스턴스 가져오기
$greetingService = $this->app->make(GreetingServiceInterface::class);
// 메서드 호출 및 결과 검증
$response = $greetingService->greet('John');
$this->assertEquals('Hello, John!', $response);
}
}
요약
- 모의 객체(Mock) 사용: Mockery와 같은 라이브러리를 사용하여 가짜 객체를 생성하고 테스트합니다. 이를 통해 의존성 주입된 객체의 동작을 검증할 수 있습니다.
- 서비스 컨테이너를 통한 테스트: 라라벨의 서비스 컨테이너를 이용하여 실제 인스턴스를 생성하고 테스트합니다. 이를 통해 서비스의 실제 동작을 검증할 수 있습니다.
Q1: Mock 객체와 실제 객체를 사용하는 테스트의 장단점은 무엇인가요?
Q2: 테스트 시 의존성 주입의 역할과 중요성은 무엇인가요?
Q3: 라라벨에서 더 복잡한 서비스나 클래스를 테스트할 때 어떤 전략을 사용할 수 있나요?
You wanna more detailed information?
모킹
https://darkghosthunter.medium.com/php-10-tips-to-use-for-mockery-33673ba01321
- 정적 메서드는 피해라
테스트를 할 때마다 문제가 발생할 수 있는 가능성을 만든다
정적 속성에는 수 많은 문제가 있으며 테스트 가능성도 그 중 하나다. 따라서 정적 속성을 상수처럼 취급하거나, 전체 앱 라이플 사이클에서 한번만 설정해야 하는 값이거나 테스트 내부에서만 독점적으로 취급하지 않는 한 사용하지 말자
다른 방법이 없다면 가능한 한 객체의 원래 상태를 항상 재설정 하자
-
구문을 더 짧게 해라
-
몇 년 전, Mockery는 테스트 코드에서 유용하지 않은 일부 줄을 제거할 수 있는 expects()및 메서드를 구현했습니다.allows()
기존 구문과 비교했을 때, 새로운 현대 구문은 키보드 입력을 줄여주고 더 이해하기 쉽게 만들어줍니다.
존경받는 개발자라면 모든 메서드에 대해 객체를 모의하고 항상 자체를 반환하라고 말할 것입니다. 이는 메서드 수만큼만 증가하므로 수십 개가 있으면 꽤 지저분해질 수 있습니다.
대신 메서드의 인수를 무시하고도 올바른 순서로 호출되도록 하려는 경우 -> 을 사용하여 모든 메서드를 한 번에 연결할 수 있습니다
. 주문방법 어떤 객체에서는 다른 메소드를 호출한 후에 다른 메소드를 호출하면 역순으로 호출한 경우와 다른 결과가 나옵니다. 예를 들어, 뺄셈 후에 곱하는 것은 뺄셈을 한 다음 곱하는 것과 다릅니다.
이런 경우에 이 ordered()방법을 사용하면 기대 사항이 설정된 순서대로 실행됩니다.
- 스파이는 당신의 친구입니다
전체 모의나 부분 모의를 만드는 대신 스파이를 사용할 수 있습니다. 스파이는 객체가 사용된 후 일부 메서드가 호출되었는지 여부를 확인하는 방법입니다.
예상 메서드가 호출되면 반환할 내용을 설정할 기회도 있습니다. 다행히도 Mockery는 andReturnArg()및 를 사용하여 수신한 인수에 따라 반환할 내용을 추가로 수정할 수 있습니다 andReturnUsing().
첫 번째 방법은 인수의 인덱스에 따라 인수를 그대로 반환하는 반면, 두 번째 방법은 최종 결과를 추가로 변경하기 위해 콜백을 허용합니다.