2017-04-08 19 views
0

엔티티 관리자로 공장을 테스트하려면 어떻게해야합니까? 내 컨테이너가 doctrine에서 생성 된 클래스의 인스턴스를 반환하도록해야하기 때문에 오류가 있습니다 (반환되는 내용을 모르겠습니다).종속성을 사용하여 공장을 단위 테스트하는 방법

내가 통과 할 수있는 테스트를 만들려면 어떻게해야합니까?

// factory i want to test 
public function __invoke(ContainerInterface $container, $requestedName, array $options = null) 
{ 
    $googleAppOption = $container->get(GoogleAppOptions::class); 
    $em = $container->get('doctrine.entity_manager.orm_default'); 
    return new GoogleTokenHandler($googleAppOption, new GoogleTokenClient(), $em); 
} 

//test function 
public function testReturnsTokenHandlerInstance() 
{ 
    $googleOptionsFactory = new GoogleOptionsFactory(); 
    $googleOptions = $googleOptionsFactory($this->container->reveal(), null); 
    $this->container->get(GoogleAppOptions::class)->willReturn($googleOptions); 
    $googleTokenHandlerFactory = new GoogleTokenHandlerFactory($this->container); 
    $tokenHandler = $googleTokenHandlerFactory($this->container->reveal(), null); 
    $this->assertInstanceof(GoogleTokenHandler::class, $tokenHandler); 

} 

답변

1

테스트하기 어렵다는 사실은 이것에 대해 냄새가 난다는 좋은 신호입니다. 귀하의 경우에는 주입되는 용기와 작업 할 서비스를 찾는 데 사용되는 것이 명백합니다. 이 클래스를 다시 작성하여 OptionsFactory (또는 옵션 만 더 좋음)와 EntityManager는 물론 동적으로 생성 된 GoogleClient를 생성자에 삽입하는 것이 좋습니다. 당신이 당신을 볼 수없는 어느 것도 $requestedName도 옵션 $options__invoke에 전달되는 사용할 수있는 것처럼

return new GoogleTokenHandler(
    $this->optionsFactory, 
    $this->tokenClient, 
    $this->entityManager 
); 

: 당신은 무엇에 도착할 것입니다 것은 거의 같이 보이는 호출입니다. 조금 이상하지만 시험으로 우리를 괴롭히지는 않습니다. 지금 당신은 단순히 테스트에서 서비스를 조롱하고 호출이 올바른 인스턴스를 반환 여부를 확인할 수 있습니다

public function testFactoryInvokeReturnsInstance() 
{ 
    $optionsFactory = $this->prophesize(OptionsFactory::class); 
    $tokenClient = $this->prophesize(GoogleTokenClient::class); 
    $entityManager = $this->prophesize(EntityManager::class); 

    $factory = new MyFactory(
     $optionsFactory->reveal(), 
     $tokenClient->reveal(), 
     $entityManager->reveal() 
    ); 

    $this->assertInstanceOf(GoogleTokenHandler::class, $factory->__invoke()); 
    // Alternatively you can use the __invoke-magic directly: 
    $this->assertInstanceOf(GoogleTokenHandler::class, $factory()); 
} 

당신은 당신의 클래스와 동일한 기능을 수행 할 수를하지만, 기본적으로는 컨테이너를 추가 한 다음 가져 오기를 스텁해야 - 그것으로부터 가져 오는 모든 서비스에 대한 방법. 예를 들어 스 니펫에서 엔티티 관리자가 누락되었습니다. 메소드에서 생성되는 GoogleTokenClient에 몇 가지 인수/옵션이 필요하면 해당 동작을 조롱 할 방법이 없으며 실제로 코드를 변경하지 않고 전환 할 수 없습니다. 반면 생성자에 삽입하면 컨테이너를 다른 객체로 전달하도록 다시 구성 할 수 있습니다.

후손를 들어, 전체 공장은 아마 이런 식으로 뭔가 보일 것 :

class Factory { 
    private $optionsFactory; 
    private $tokenClient; 
    private $entityManager; 

    public function __construct(GoogleTokenClient $tokenClient, ...) 
    { 
     $this->tokenClient = $tokenClient; 
     ... 
    } 

    public function __invoke() { return new GoogleTokenHandler(...); } 
} 
+0

을하지만 난 내 공장을 만드는 공장이 필요 의미? –

+0

또는 TokenHanlderFactory를 만들기 위해 내 컨트롤러에 서비스 위치 지정자를 사용해야합니까? –

+0

어떤 팩토리가 팩토리를 만들지는 모르겠지만, 일반적으로 말하자면 - 어떤 다이나믹리즘이 관련되어 있다면 "FactoryFactory"를 갖고 자바 코드베이스에서 다소 일반적 일 것입니다 (어떤 상태가 요청 사이에있을 때) . 컨트롤러에서 컨테이너를 사용하여 팩토리를 얻거나 일부 DI 컨테이너를 사용하여 TokenHandler를 직접 가져올 수 있습니다 (예 : Symfony 's Container : https://symfony.com/doc/current/service_container/factories.html – dbrumann