2013-12-20 2 views
2

문제는 같은 저장소의 다른 기능을 다루기 때문에 하나의 함수를 테스트 할 수 없다는 것입니다.종속성으로 모델이있는 laravel 저장소 테스트

  1. 하나의 기능을 동일한 저장소에서 다른 기능과 별도로 테스트해야합니까? 아니면 하나의 기능이 동일한 저장소의 다른 기능에 액세스 할 수있는 것이 정상입니까?
  2. 함수를 다른 것과 분리하여 테스트해야하는 경우 어떻게 수행 할 수 있습니까? 내가 작동하는 저장소를 모의 할 수있는 방법을 이해할 수 없기 때문입니다. 의존성을 모방하는 방법을 이해하지만 동일한 저장소에서 다른 함수를 모방하는 방법은 무엇입니까?
  3. 테스트에서 setUp 메소드에서 모델을 정확하게 조롱하고 있습니까?

코드 :

실제 세계의 바인딩 저장소 :

// Bind User repository interface 
$app->bind('MyApp\Repositories\User\UserInterface', function() { 
    return new EloquentUser(new User); 
}); 

EloquentUser.php :

public function __construct(Model $user) 
{ 
    $this->user = $user; 
} 

public function findById($id) 
{ 
    return $this->user->find($id); 
} 

public function replace($data) 
{ 
    $user = $this->findById($data['user']['id']); 

    // If user not exists, create new one with defined values. 
    if (! $user) { 
     return $this->create($data); 
    } else { 
     return $this->update($data); 
    } 
} 

public function create($data) 
{ 
    $user = $this->user->create($data['user']); 

    if ($user) { 

     return $this->createProfile($user, $data['profile']); 

    } else { 

     return false; 
    } 
} 

private function createProfile($user, $profile) 
{ 
    return $user->profile()->create($profile); 
} 

public function update($user, $data) 
{ 
    foreach ($data['user'] as $key => $value) { 
     $user->{$key} = $value; 
    } 

    if (isset($data['profile']) && count($data['profile']) > 0) { 

     foreach ($data['profile'] as $key => $value) { 
      $user->profile->$key = $value; 
     } 
    } 

    return ($user->push()) ? $user : false; 
} 

EloquentUserTest.php

public function setUp() 
{ 
    parent::setUp(); 
    $this->user = Mockery::mock('Illuminate\Database\Eloquent\Model', 'MyApp\Models\User\User'); 
    App::instance('MyApp\Models\User\User', $this->user); 
    $this->repository = new EloquentUser($this->user); 
} 

public function testReplaceCallsCreateMethod() 
{ 
    $data = [ 
     'user' => [ 
      'id' => 1, 
      'email' => '[email protected]', 
     ], 
     'profile' => [ 
      'name' => 'John Doe', 
      'image' => 'abcdef.png', 
     ], 
    ]; 

    // Mock the "find" call that is made in findById() 
    $this->user->shouldReceive('find')->once()->andReturn(false); 

    // Mock the "create" call that is made in create() method 
    $this->user->shouldReceive('create')->once()->andReturn(true); 

    // Run replace method that i want to test 
    $result = $this->repository->replace($data); 

    $this->assertInstanceOf('Illuminate\Database\Eloquent\Model', $result, 'Should be an instance of Illuminate\Database\Eloquent\Model'); 
} 

내가 가진이 테스트를 실행하는 경우 :

private function createProfile($user, $profile) 
{ 
    return $user->profile()->create($profile); 
} 

내가 조롱해야하나요 :

Fatal error: Call to a member function profile() on a non-object in C:\Htdocs\at.univemba.com\uv2\app\logic\Univemba\Repositories\User\EloquentUser.php on line 107 

그래서이 테스트는 EloquentUser.php에서 기능을 터치하려고하는 것을 의미한다을 createProfile? profile()이 발견되지 않기 때문에. 그리고이 작업을 수행해야한다면이 기능이 내가 테스트중인 저장소와 동일하기 때문에 어떻게 할 수 있습니까?

답변

7

질문이 해결되었습니다. 하나의 모델 인스턴스를 추가하여 조롱 된 방법으로 전달하면됩니다.

내 작업 설정 방법 :

public function setUp() 
{ 
    parent::setUp(); 

    $this->user = Mockery::mock('MyApp\Models\User\User'); 

    App::instance('MyApp\Models\User\User', $this->user); 

    $this->repository = new EloquentUser($this->user); 
} 

작동 시험 방법 :

public function testReplaceCallsCreateMethod() 
{ 
    $data = [ 
     'user' => [ 
      'id' => 1, 
      'email' => '[email protected]', 
      'password' => 'plain', 
     ], 
     'profile' => [ 
      'name' => 'John Doe', 
      'image' => 'abcdef.png', 
     ], 
    ]; 

    // Mock Model's find method 
    $this->user->shouldReceive('find')->once()->andReturn(false); 

    // Create new Model instance 
    $mockedUser = Mockery::mock('MyApp\Models\User\User'); 

    // Mock Models profile->create and pass Model as a result of a function 
    $mockedUser->shouldReceive('profile->create')->with($data['profile'])->andReturn($mockedUser); 

    // Pass second instance Model as a result 
    $this->user->shouldReceive('create')->once()->andReturn($mockedUser); 

    // Now all $user->profile is properly mocked and will return correct data 
    $result = $this->repository->replace($data); 

    $this->assertInstanceOf('Illuminate\Database\Eloquent\Model', $result, 'Should be an instance of Illuminate\Database\Eloquent\Model'); 
}