1

I have DocumentService class like this:

namespace App\Services;

use App\Api\StorageServiceInterface;

class DocumentService
{

    private $storageService;

    function __construct(StorageServiceInterface $storageService)
    {
        $this->storageService = $storageService;
    }

    public function createFolder(User $user)
    {
        $folderData = $this->storageService->createFolder(
            '/Users/' . $user->email
        );

        $user->folder = $folderData['folder_id'];
        $user->save();

        return $user->folder;
    }
}

Partial implmentation of the LocalStorageService.

namespace App\Api;

class LocalStorageService implements StorageServiceInterface
{
    public function createFolder($folder)
    {
        ...

        return ['folder_id' => $folder_id, 'folder_path' => $folder_path];
    }
}

I'm testing the DocumentService class. I'm trying to mock the createFolder() method on the LocalStorageService which implements StorageServiceInterface.

How do I configure this stub to return the array with PHPUnit?

I've tried this: (partial code from my test)

namespace Tests\Unit\Services;

use App\User;
use App\Api\LocalStorageService;

public function testCreateFolder()
{
    $user = factory(User::class)->make();

    $localStorageService = $this->createMock(LocalStorageService::class);

    $localStorageService->method('createFolder')
            ->willReturn(array('folder_id' => 'random_id', 'folder_path' => ("/Users/" . $user->email)));
}

But I'm only getting random_id.

Raghavendra N
  • 1,359
  • 1
  • 18
  • 36
  • update question include `StorageServiceInterface` as part of the [mcve] used to reproduce the problem. – Nkosi Jan 15 '18 at 05:09
  • https://phpunit.de/manual/current/en/test-doubles.html#test-doubles.mock-objects – Nkosi Jan 15 '18 at 05:18
  • Added the minimal code. Thanks. I did go through the documentation, but could not find how to return array from mocked method. – Raghavendra N Jan 15 '18 at 05:23
  • 2
    You are mocking the wrong thing. mock the abstraction not the implementation. – Nkosi Jan 15 '18 at 05:24
  • Sounds good. I did go through this: https://stackoverflow.com/questions/9226323/mocking-a-class-vs-mocking-its-interface. I'll mock the interface. Just curious if it is possible to make sure the mocked method returns array in phpunit. – Raghavendra N Jan 15 '18 at 05:35

1 Answers1

0

Although it should work with classes as well as interfaces, interfaces should be preferred as this is what client of the interface expects.

This following should work:

public function testCreateFolder()
{
    $user = factory(User::class)->make();
    $folderPath = '/Users/' . $user->email;

    $localStorageService = $this->createMock(StorageServiceInterface::class);

    $localStorageService
        ->expects($this->once())
        ->method('createFolder')
        ->with($folderPath)
        ->willReturn(
            ['folder_id' => 'random_id', 'folder_path' => $folderPath]
        );


     $documentService = new DocumentService($localStorageService);
     $documentService->createFolder($user);
}

By adding the with() call you're making sure only if the path is passed it returns the given array.

Jakub Zalas
  • 35,761
  • 9
  • 93
  • 125