How testing instance of Exception with phpunit - phpunit

I have this class to testing.
class IpSecurity
{
/** #var array */
private $ipsAllow;
public function __construct(array $ipsAllow)
{
$this->ipsAllow = $ipsAllow;
}
/**
* #param string $clientIp
*
* #return NotFoundHttpException
*/
public function checkIp($clientIp)
{
if (!in_array($clientIp, $this->ipsAllow)) {
throw new NotFoundHttpException('NOT FOUND');
}
}
}
I write a test for testing excettion.
class IpSecurityTest extends \PHPUnit_Framework_TestCase
{
/** #var IpSecurity */
private $ipSecurity;
private $ipsAllow = array(
'192.168.200.21'
);
public function setUp()
{
$this->ipSecurity = new IpSecurity($this->ipsAllow);
}
/**
* #test
* #expectedException(Symfony\Component\HttpKernel\Exception\NotFoundHttpException)
*/
public function invalidClientIp()
{
$this->ipSecurity->checkIp('127.0.0.1');
}
}
This is the test output:
PHPUnit 3.7.37 by Sebastian Bergmann.
Configuration read from /home/pablo/dev/www/app/phpunit.xml
E
Time: 36 ms, Memory: 4.50Mb
There was 1 error:
1) ws\AmneiBundle\Tests\Services\IpSecurityTest::invalidClientIp
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: NOT FOUND
I want test the exception class, not if result is a exception.

You can test it with this code
try
{
$this->ipSecurity->checkIp('127.0.0.1');
}catch( Exception $e )
{
if (!($e instanceof NotFoundHttpException)) {
$this->fail("Unexpected Exception type throwed");
}
}

Related

How to mock variables in a PHPUnit Coverage Test?

I'm writing PHPUnit tests and running coverage tests. I admit its very difficult to have 100% coverage, however, I'd like to get as close as possible. In a following scenario, how to mock variables in a clause in order to test the code block?
class CalendarClientService
{
/** #var array SCOPES */
public const SCOPES = [Google_Service_Calendar::CALENDAR];
/** #var string ACCESS_TYPE */
public const ACCESS_TYPE = "offline";
/** #var string CALENDAR_ID */
public const CALENDAR_ID = "primary";
/** #var int MAX_RESULTS */
public const MAX_RESULTS = 25;
/** #var string ORDER_BY */
public const ORDER_BY = "startTime";
/** #var bool SINGLE_EVENTS */
public const SINGLE_EVENTS = true;
/** #var string|null TIME_MIN */
public const TIME_MIN = null;
/** #var bool CACHE_TIME_TO_LIVE */
public const CACHE_TIME_TO_LIVE = 604800;
/** #var string */
public string $clientSecretPath = "";
/** #var StorageAdapterFactoryInterface */
protected StorageAdapterFactoryInterface $storageAdapterFactory;
/** #var StorageInterface */
protected StorageInterface $storageInterfaceCache;
/**
* CalendarClientService constructor.
* #param string $clientSecretPath
* #param StorageAdapterFactoryInterface $storageAdapterFactory
* #param StorageInterface $storageInterfaceCache
*/
public function __construct(
string $clientSecretPath,
StorageAdapterFactoryInterface $storageAdapterFactory,
StorageInterface $storageInterfaceCache
) {
$this->clientSecretPath = $clientSecretPath;
$this->storageAdapterFactory = $storageAdapterFactory;
$this->storageInterfaceCache = $storageInterfaceCache;
}
/** #return string */
public function getClientSecretPath()
{
return $this->clientSecretPath;
}
/** #param string $secretFile */
public function setClientSecretPath(string $secretFile)
{
$this->clientSecretPath = $secretFile;
}
/**
* #param array
* #return Google_Service_Calendar_Event
*/
public function getGoogleServiceCalendarEvent($eventData)
{
return new Google_Service_Calendar_Event($eventData);
}
/**
* #param string
* #return Google_Service_Calendar_EventDateTime
*/
public function getGoogleServiceCalendarEventDateTime($dateTime)
{
$eventDateTime = new Google_Service_Calendar_EventDateTime();
$eventDateTime->setDateTime(Carbon::parse($dateTime)->toW3cString());
$eventDateTime->setTimeZone(Carbon::parse($dateTime)->timezone->getName());
return $eventDateTime;
}
/**
* #param Google_Client $client
* #return Events
*/
public function getGoogleServiceCalendarResourceEvents(Google_Client $client)
{
$service = new Google_Service_Calendar($client);
return $service->events;
}
/**
* #param int
* #return array
* #throws Exception
* #throws ExceptionInterface
*/
public function getEventData($id)
{
$client = $this->getClient();
if (!$this->authenticateClient($client)) {
return [
"error" => "authentication",
"url" => filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL),
];
}
$service = $this->getGoogleServiceCalendarResourceEvents($client);
return ["event" => $service->get(self::CALENDAR_ID, $id)];
}
/**
* #return Google_Client
* #throws Exception
*/
public function getClient()
{
$client = new Google_Client();
$client->setApplicationName(Module::MODULE_NAME);
$client->setScopes(self::SCOPES);
$client->setAuthConfig($this->clientSecretPath);
$client->setAccessType(self::ACCESS_TYPE);
return $client;
}
/**
* #param Google_Client $client
* #return bool
* #throws ExceptionInterface
*/
public function authenticateClient(Google_Client $client)
{
if ($this->storageInterfaceCache->hasItem("api_access_token")) {
$accessToken = json_decode($this->storageInterfaceCache->getItem("api_access_token"), true);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
}
}
if ($client->isAccessTokenExpired()) {
$tokenValid = false;
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$accessToken = $client->getAccessToken();
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$tokenValid = true;
} else {
$helper = new Helper();
if(!$helper->verifyAuthCode($_GET["code"])){
return $tokenValid;
}
$authCode = $_GET["code"];
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
$tokenValid = true;
}
}
} else {
$tokenValid = true;
}
return isset($tokenValid) ? $tokenValid : false;
}
I want to test this 6th line from top in authenticateClient method and want to mock this clause $accessToken["error"] == "invalid_grant" || empty($accessToken).
Now how to go about it?
Edit: Here's a test that I've written. Now whatever value I'm mocking in the $this->storageInterfaceCacheMock->method("getItem"), it always returns empty $accessToken. I've also attached the image for better understanding of what's happening and what I want.
public function testGetEventDataReturnsArrayOnSuccessfulAuthenticateClientThroughCache()
{
$this->storageInterfaceCacheMock->method("hasItem")->willReturn(true);
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"ya29.a0ARrdaM99pJTf1XzmD1ngxAH3XJud8lvHb0aTaOOABYdfdhsdfgsdfgVD9OoH4heiKoskDF7DMkHj1_aPuWIO5TE14KHJidFf66xwn_pTCkkSow6Kg4lRHwGrNQBQGI8sPlgnFO5U5hJvYdqgxDMHEqw1TER2w","expires_in":3599,"scope":"https:\/\/www.googleapis.com\/auth\/calendar","token_type":"Bearer","created":1637312218,"refresh_token":"1\/\/03psr5omKiljUCgYFDHDGJHGSHSNwF-L9Iraor5zcfe-h3BeCHSFGSDFGDGJHjy4UnEtKj974LXthS5bWexQcjviVGfJsdfGHSHgIrDn6Yk"}'));
$this->assertIsArray($this->calendarClientService->getEventData(1));
}
Another test which isn't performing as per required is mentioned below. (also visible in the screenshot)
public function testAccessTokenIsExpiredAndGotRefreshToken()
{
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(true);
$this->googleClientMock->method("fetchAccessTokenWithRefreshToken")->willReturnSelf();
$this->googleClientMock->method("getAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}
I believe you want json_decode you don't need double encode here:
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"...."}'));
just
$this->storageInterfaceCacheMock->method("getItem")->willReturn('{"access_token":"...."}');
Here's how I resolved the issue and got the test to be successful.
I declared a dummy ACCESS_TOKEN as below and then used in the test method.
class CalendarControllerTest extends AbstractApplicationTestCase
{
/** #var string CLIENT_SECRET */
public const CLIENT_SECRET = __DIR__ . "/../_fixtures/config/client_secret.json";
/** #var string CLIENT_SECRET */
public const ACCESS_TOKEN = [
"access_token" => "test-data",
"expires_in" => 3592,
"scope" => "https://www.googleapis.com/auth/calendar",
"token_type" => "Bearer",
"created" => 1640858809,
];
...
...
...
}
public function setUp(): void
{
parent::setUp();
$this->googleClientMock = $this->getMockBuilder(Google_Client::class)
->disableOriginalConstructor()
->onlyMethods(
[
"isAccessTokenExpired",
"setAuthConfig",
"getRefreshToken",
"fetchAccessTokenWithRefreshToken",
"fetchAccessTokenWithAuthCode",
"getAccessToken",
"setAccessToken",
]
)
->getMock();
$this->googleServiceCalendarResourceEventsMock = $this->getMockBuilder(Events::class)
->disableOriginalConstructor()
->onlyMethods(["get"])
->getMock();
$this->googleServiceCalendarEventMock = $this->getMockBuilder(Event::class)
->disableOriginalConstructor()
->getMock();
$this->storageInterfaceCacheMock = $this->getMockForAbstractClass(StorageInterface::class);
$this->container->setAllowOverride(true);
$this->container->setService(Google_Client::class, $this->googleClientMock);
$this->container->setService(Events::class, $this->googleServiceCalendarResourceEventsMock);
$this->container->setService(Event::class, $this->googleServiceCalendarEventMock);
$this->container->setService(StorageInterface::class, $this->storageInterfaceCacheMock);
$this->container->setAllowOverride(true);
$this->googleClientMock->method("setAuthConfig")->willReturn(true);
$this->calendarClientService = $this->container->get("ServiceManager")->get(CalendarClientService::class);
$this->calendarClientService->setClientSecretPath(CalendarControllerTest::CLIENT_SECRET);
}
/** #throws ExceptionInterface */
public function testAccessTokenIsExpiredAndFailureToRefreshTokenWillGenerateNewAccessToken()
{
$this->calendarClientService->setAuthCode(CalendarControllerTest::DEFAULT_TESTING_VALUE);
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(false);
$this->googleClientMock->method("fetchAccessTokenWithAuthCode")->willReturn(
CalendarControllerTest::ACCESS_TOKEN
);
$this->storageInterfaceCacheMock->method("setItem")->willReturn(true);
$this->googleClientMock->method("setAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}

Symfony mock service when test console command

How to mock some service when test console command. I have some console command, in this command I get some service and I want mock this service
console command
const APP_SATISFACTION_REPORT = 'app:satisfactionrepor';
protected function configure()
{
$this
->setName(self::APP_SATISFACTION_REPORT)
->setDescription('Send Satisfaction Report');
}
/**
* #param InputInterface $input
* #param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$container = $this->getContainer();
$serviceCompanyRepo = $container->get('app.repository.orm.service_company_repository');
$satisfactionReport = $container->get('app.services.satisfaction_report');
/** #var ServiceCompany $serviceCompany */
foreach ($serviceCompanyRepo->findAll() as $serviceCompany) {
try {
$satisfactionReport->sendReport($serviceCompany);
} catch (\Exception $e) {
$io->warning(sprintf(
'Failed to send satisfaction report for service company with ID %s',
$serviceCompany->getId()
));
}
}
}
and my tests
/** #var Console\Application $application */
protected $application;
protected $container;
/** #var BufferedOutput $output */
protected $output;
/**
* #var ServiceCompanyRepository
*/
private $serviceCompanyRepository;
prepare console command
public function setUp()
{
parent::setUp();
$entityManager = $this->getEntityManager();
$this->serviceCompanyRepository = $entityManager->getRepository(ServiceCompany::class);
static::bootKernel();
$this->container = static::$kernel->getContainer();
$this->application = new Console\Application(static::$kernel);
$this->application->setAutoExit(false);
$master = new SatisfactionReportCommand();
$this->application->add($master);
}
public function setUpMaster() {
$this->output = new BufferedOutput();
$this->application->run(new ArgvInput([
'./bin/console',
SatisfactionReportCommand::APP_SATISFACTION_REPORT,
]), $this->output);
}
public function testGetMasterOutput()
{
$this->loadFixture(ServiceCompany::class);
/** #var ServiceCompany[] $serviceCompanies */
$serviceCompanies = $this->serviceCompanyRepository->findAll();
$this->assertCount(2, $serviceCompanies);
$client = self::createClient();
mock service app.services.satisfaction_report
$service = $this->getMockService($serviceCompanies);
and set it in container
$client->getContainer()->set('app.services.satisfaction_report', $service);
$this->setUpMaster();
$output = $this->output->fetch();
}
protected function getMockService($serviceCompanies)
{
$service = $this->getMockBuilder(SatisfactionReport::class)
->setMethods(['sendReport'])
->disableOriginalConstructor()
->getMock();
$service
->expects($this->exactly(2))
->method('sendReport')
->withConsecutive(
[$serviceCompanies[0]],
[$serviceCompanies[1]]
);
return $service;
}
How to mock app.services.satisfaction_report? Set in container app.services.satisfaction_report not help me
I had same problem but I resolved it.
I have base class:
class TestCase extends WebTestCase
{
/** #var Application */
private $application;
private $mailServiceMock;
protected function setMailService(MailService $mailServiceMock): void
{
$this->mailServiceMock = $mailServiceMock;
}
protected function getApplication(): Application
{
static::bootKernel();
static::$kernel->getContainer()->get('test.client');
$this->setMocks();
$this->application = new Application(static::$kernel);
$this->application->setCatchExceptions(false);
$this->application->setAutoExit(false);
return $this->application;
}
protected function execute(string $action, array $arguments = [], array $inputs = []): CommandTester
{
$tester = (new CommandTester($this->getApplication()->find($action)))->setInputs($inputs);
$tester->execute($arguments);
return $tester;
}
private function setMocks(): void
{
if ($this->mailServiceMock) {
static::$kernel->getContainer()->set('mail', $this->mailServiceMock);
}
}
}
And test class
class SendEmailCommandTest extends TestCase
{
public function testExecuteSendingError(): void
{
$mailServiceMock = $this->getMockBuilder(MailService::class)->disableOriginalConstructor()
->setMethods(['sendEmail'])->getMock();
$mailServiceMock->method('sendEmail')->willThrowException(new \Exception());
$this->setMailService($mailServiceMock);
$tester = $this->execute(SendEmailCommand::COMMAND_NAME, self::NORMAL_PAYLOAD);
$this->assertEquals(SendEmailCommand::STATUS_CODE_EMAIL_SENDING_ERROR, $tester->getStatusCode());
}
}
As you can see I set mail service right after booting kernel.
And here you can see my services.yaml:
services:
mail.command.send.email:
autowire: true
class: App\Command\SendEmailCommand
arguments: ["#logger", "#mail"]
tags:
- {name: console.command, command: "mail:send.email"}
If you create the commands as a service, where the framework injects the services automatically (either autowired, or with an explicit argument list) into a constructor (tip: in the command, call the parent::__construct()), then the test can create whatever mock or other replacement service that matches the parameter typehint (or interface).
here is my example class:
class MainCommandTest extends IntegrationTestCase
{
/**
* #var MainCommand
*/
protected $subject;
/**
* #var Application
*/
protected $application;
/**
* sets test subject
*
* #return void
*/
public function setUp()
{
parent::setUp();
static::bootKernel();
$readStreams = new ReadStreams();
$udpStreamMock = $this->getMockBuilder(UdpStream::class)->disableOriginalConstructor()->setMethods(['readIncomingStreams'])->getMock();
$udpStreamMock->expects($this->once())->method('readIncomingStreams')->willReturn($readStreams);
static::$kernel->getContainer()->set(UdpStream::class, $udpStreamMock);
$application = new Application($this::$kernel);
$this->subject = $this->getService(MainCommand::class);
$application->add( $this->subject);
$this->application = $application;
}
/**
* Tests command in $subject command,
*
* #return void
*/
public function testCommand()
{
$command = $this->application->find( $this->subject->getName());
$commandTester = new CommandTester($command);
$commandTester->execute(
[
'command' => $this->subject->getName()
]
);
$this->stringContains($commandTester->getDisplay(true), 'finished');
$this->assertEquals($commandTester->getStatusCode(), 0);
}
}

How to set or get value from cache in symfony2.8?

In my service.yml
cache:
class: Doctrine\Common\Cache\PhpFileCache
arguments: [%kernel.cache_dir%]
And in my controller
$cache = $this->get('cache');
if ($cache->fetch($cache_key) != NULL) {
// mycode
}
My SilencedError is
1-include(\app\cache\dev\30\446f637472696e654e616d65737061636543616368654b65795b5d.doctrinecache.php): failed to open stream: No such file or directory
you are trying to fetch an entry without checking if it exists. Use $cache->contains($cache_key) before fetching the entry.
As the PhpFileCache class extends FileCache which extends CacheProvider you should check the classes for available functions to create and retrieve cache entries:
/**
* {#inheritdoc}
*/
public function fetch($id)
{
...
}
/**
* {#inheritdoc}
*/
public function fetchMultiple(array $keys)
{
...
}
/**
* {#inheritdoc}
*/
public function saveMultiple(array $keysAndValues, $lifetime = 0)
{
...
}
/**
* {#inheritdoc}
*/
public function contains($id)
{
...
}
/**
* {#inheritdoc}
*/
public function save($id, $data, $lifeTime = 0)
{
...
}

phpspec doctrine queryBuilder - mock

I'm writing a test in PHPSpec 2.0.0 that would use Doctrine query builder in a Symfony application. This is my class:
class RedirectHandle
{
/**
* #var string
*/
private $kernelEnvironment;
/**
* #var ContainerInterface
*/
private $container;
/**
* RedirectHandle constructor.
* #param $env
* #param ContainerInterface $containerInterface
*/
public function __construct($env, ContainerInterface $containerInterface)
{
$this->kernelEnvironment = $env;
$this->container = $containerInterface;
}
public function handleUrl($url)
{
if ($this->kernelEnvironment === "dev") {
$em = $this->container->get("doctrine")->getEntityManager();
return $em->createQuery("SELECT a FROM module_redirect a WHERE url_from_redirect = :url ")
->setParameter('url', $url)
->getSingleScalarResult();
}
return false;
}
}
Here is my phpspec test:
class RedirectHandleSpec extends ObjectBehavior
{
function let($kernel,$container,$queryBuilder,$em,$redirectHandle)
{
$env = "dev";
$kernel->beADoubleOf('Symfony\Component\HttpKernel\Kernel');
$kernel->getEnvironment()->willReturn($env);
$queryBuilder->beADoubleOf('Doctrine\ORM\QueryBuilder');
$container->beADoubleOf('Symfony\Component\DependencyInjection\ContainerInterface');
$redirectHandle->beADoubleOf('Kei\WebsiteBundle\Tools\Redirect\RedirectHandle');
$em->beADoubleOf('Doctrine\ORM\EntityManager');
$kernel->getContainer()->willReturn($container);
$this->beConstructedWith($env,$container);
}
function it_is_initializable()
{
$this->shouldHaveType('Kei\WebsiteBundle\Tools\Redirect\RedirectHandle');
}
function it_is_init_redirect_when_env_is_dev($container,$queryBuilder,$em)
{
$container->get("doctrine")->willReturn($queryBuilder);
$em->createQuery(Argument::any())->willReturn($em);
$this->handleUrl("test")->shouldBeReturn(true);
}
}
When I ran the test, I got the following error:
1PHP Fatal error: Uncaught Error: Call to a member function createQuery() on null in /var/www/kei-site/src/Kei/WebsiteBundle/Tools/Redirect/RedirectHandle.php:37
Stack trace:
#0 [internal function]: Kei\WebsiteBundle\Tools\Redirect\RedirectHandle->handleUrl('test')
#1 /var/www/kei-site/vendor/phpspec/phpspec/src/PhpSpec/Wrapper/Subject/Caller.php(260): call_user_func_array(Array, Array)
#2 /var/www/kei-site/vendor/phpspec/phpspec/src/PhpSpec/Wrapper/Subject/Caller.php(97): PhpSpec\Wrapper\Subject\Caller->invokeAndWrapMethodResult(Object(Kei\WebsiteBundle\Tools\Redirect\RedirectHandle), 'handleUrl', Array)
#3 /var/www/kei-site/vendor/phpspec/phpspec/src/PhpSpec/Wrapper/Subject.php(187): PhpSpec\Wrapper\Subject\Caller->call('handleUrl', Array)
#4 [internal function]: PhpSpec\Wrapper\Subject->__call('handleUrl', Array)
#5 /var/www/kei-site/vendor/phpspec/phpspec/src/PhpSpec/ObjectBehavior.php(136): call_user_func_array(Array, Array)
#6 /var/www/kei-site/spec/Kei/WebsiteBundle/Tools/Redirect/RedirectHandleSpec.php(40): PhpSpec\Obj in /var/www/kei-site/src/Kei/WebsiteBundle/Tools/Redirect/RedirectHandle.php on line 37
What should I do to fix this?
class RedirectHandle
{
/**
* #var string
*/
private $kernelEnvironment;
/**
* #var
*/
private $container;
/**
* RedirectHandle constructor.
* #param $env
* #param ContainerInterface $containerInterface
*/
public function __construct($env,ContainerInterface $containerInterface)
{
$this->kernelEnvironment = $env;
$this->container = $containerInterface;
}
/**
*
*/
public function handleUrl($url)
{
if ($this->kernelEnvironment === "dev") {
$em = $this->container->get("doctrine")->getEntityManager();
$query = $em->createQuery("SELECT a FROM KeiWebsiteBundle:Carrier a");
return true;
}
return false;
}
}
Phpspec code after refactor:
class RedirectHandleSpec extends ObjectBehavior
{
function let($kernel,$container,$queryBuilder,$em)
{
$env = "dev";
$kernel->beADoubleOf('Symfony\Component\HttpKernel\Kernel');
$queryBuilder->beADoubleOf('Doctrine\ORM\QueryBuilder');
$container->beADoubleOf('Symfony\Component\DependencyInjection\ContainerInterface');
$em->beADoubleOf('Doctrine\ORM\EntityManager');
$this->beConstructedWith($env,$container);
}
function it_is_initializable()
{
$this->shouldHaveType('Kei\WebsiteBundle\Tools\Redirect\RedirectHandle');
}
/**
* Przekierowuje strone jesli srodowisko jest dev
*/
function it_is_init_redirect_when_env_is_dev($container,$queryBuilder,$em)
{
$container->get("doctrine")->willReturn($queryBuilder);
$em->createQuery(Argument::any())->willReturn(new Query($em->getWrappedObject()));
$this->handleUrl("test");
}
}

method data provider executes before setup

i have test class like this
class CallTest extends WebTestCase
{
/** #var \Doctrine\Common\DataFixtures\Executor\AbstractExecutor */
protected $executor;
public function setUp()
{
$this->executor = $this->loadFixtures(array('Tests\Fixtures\LoadCallData'));
}
/**
* #dataProvider callProvider
*/
public function testCall($service, $token, $fileId, $phone, $callTime)
{
// some code for testing
}
/**
* Данные для проверки
* #return array
*/
public function callProvider()
{
$devices = $this->devicesProvider();
// providing some data
return array(.....);
}
public function devicesProvider()
{
return array_map(
function ($device) use($service) {
return array($service, $device);
},
$devices
);
}
}
problem is that setUp method not rans

Resources