정적 메소드와 함께 서비스 클래스를 사용하지 마십시오

4372 단어 phplaraveloopwebdev
이 게시물의 컨텍스트에서 서비스 클래스는 도메인 논리를 캡슐화하는 데 사용되는 클래스입니다. 예를 들어 새 블로그 게시물을 만들기 위해 끝점을 만들 때 많은 사람들이 컨트롤러에서 직접 작동하는 대신 서비스 클래스 메서드 내부에 새 게시물을 만드는 핵심 논리를 배치하도록 선택합니다.

개발자가 해당 논리를 캡슐화하는 이유는 일반적으로 프로젝트 내의 다른 위치에서 재사용할 수 있기 때문입니다. 예를 들어 블로그 게시물을 만들 때 프런트 엔드 구현 또는 API를 통해 가능할 수 있습니다.

정적 메소드가 처음에 사용되는 이유



이 패턴이 사용되는 이유를 정확히 파악하기는 어렵지만 내 추측은 다음과 같습니다. 오버헤드가 없는 깔끔한 디자인(Facade 패턴이 제공할 수 있는 것과 같은)과 비슷합니다. 클래스를 사용 가능한 퍼사드로 전환하기 위해 상용구를 작성하는 대신 메서드 앞에 static 키워드를 추가하는 것이 더 쉽습니다. 외관처럼 깨끗해 보입니다. 못생긴 의존성 주입을 할 필요가 없습니다.

class PostService
{
  public static function create()
  {
    // do some creating...
  }
}

class PostController
{
  public function store(Request $request)
  {
    // validate and whatever else...
    PostService::create($request->all());

    return back();
  }
}


멋지지 않나요?

당신이 그것을 하지 말아야 하는 이유



테스트.

이러한 서비스 클래스를 활용하는 모든 것을 테스트하는 데 엄청난 시간이 걸릴 것입니다. 서비스를 사용하는 컨트롤러 메서드를 테스트한다고 가정해 보겠습니다. 이 서비스는 배후에서 많은 복잡한 논리를 수행합니다. 테스트 내에서 서비스가 실패 없이 실행되는 데 필요한 모든 것을 준비해야 합니다. 모두 이 관련 없는 다른 것을 테스트하기 위한 것입니다.

mock a static method 에 대한 (소르타) 방법이 있지만 권장되지 않으며 Mockery 문서에 직접 명시되어 있습니다.

이야기의 교훈은 길에서 많은 골칫거리를 피하고 좋은 구식 의존성 주입을 고수하는 것입니다. Laravel을 사용하면 컨테이너를 사용하여 모든 종속성을 자동으로 해결하는 것이 어쨌든 간단합니다.

가장 쉬운 대안




class PostController
{
  public function store(Request $request, PostService $service)
  {
    // validate and whatever else...
    $service->create($request->all());

    return back();
  }
}


솔직히 말해서 위의 코드 블록은 훨씬 더 나쁘지 않습니다. 특히 테스트가 얼마나 더 쉬워질지 생각하면 더욱 그렇습니다.

테스트 방법



Laravel은 컨테이너를 활용하여 종속성을 자동으로 해결하므로 a way to hijack that and sub in a mocked version 을 제공했습니다.

$this->mock(PostService::class, function (MockInterface $mock) {
    $mock->shouldReceive('create')->once();
});

좋은 웹페이지 즐겨찾기