I am trying to write a test for a function which returns false or object.
class Environment {
protected $db , $env, $envMapper= "";
public function __construct($dbConnection) {
$this->db = $dbConnection;
$this->setMapper($this->db);
}
public function setMapper($db){
$this->envMapper=new DB\SQL\Mapper($this->db,'environment');
}
public function save($envName) {
$this->envMapper->name = $envName;
return $this->envMapper->save();
}
/**
* #param $envId
*/
public function get($envId) {
}
/***
* #param $envName
*/
public function getByName($envName) {
}
}
Tests:
class EnvironmentTest extends PHPUnit_Framework_TestCase {
protected $db = "";
public function setup()
{
$this->db = $this->getMockBuilder('SqlHelper')
->setMethods(array('connect'))
->getMock();
}
public function testSave() {
$object = new StdClass();
$env = new Environment($this->db);
$this->assertEquals($object, $env->save('Test'));
}
}
I am not sure how should I change so that it would be testable, it always return
EnvironmentTest::testSave
PHPUnit_Framework_MockObject_RuntimeException: You cannot serialize or
unserialize PDO instances
Related
I'm taking over someone's code and I don't understand something about the voting.
Here is the PhotosController class:
class PhotosController extends Controller
{
/**
* #Route("/dashboard/photos/{id}/view", name="dashboard_photos_view")
* #Security("is_granted('view.photo', photo)")
* #param Photo $photo
* #param PhotoRepository $photoRepository
*/
public function index(Photo $photo, PhotoRepository $photoRepository)
{
$obj = $photoRepository->getFileObjectFromS3($photo);
header("Content-Type: {$obj['ContentType']}");
echo $obj['Body'];
exit;
}
Here is the voter class:
class PhotoVoter extends Voter
{
const VIEW = 'view.photo';
protected function supports($attribute, $subject)
{
if (!$subject instanceof Photo) {
return false;
}
if (!in_array($attribute, array(self::VIEW))) {
return false;
}
return true;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
return $subject->getUser()->getId() === $token->getUser()->getId();
}
}
I don't understand what the
, photo
is for in the PhotosController class. And in PhpStorm I get "cannot find declaration" when I try to go to the "is_granted" declaration.
I decided, that it will be fine if I use data providers but when i try to generate code coverage whole tested class has 0% coverage.. Can someone tell me why?
Test class:
class AuthorDbManagerTest extends AbstractDbManagerTest
{
public function setUp()
{
parent::setUp();
}
/**
* #dataProvider instanceOfProvider
* #param bool $isInstanceOf
*/
public function testInstances(bool $isInstanceOf)
{
$this->assertTrue($isInstanceOf);
}
public function instanceOfProvider()
{
$manager = new AuthorDbManager($this->getEntityManagerMock());
return [
"create()" => [$manager->create() instanceof Author],
"save()" => [$manager->save(new Author()) instanceof AuthorDbManager],
"getRepository" => [$manager->getRepository() instanceof EntityRepository],
];
}
}
Tested class:
class AuthorDbManager implements ManagerInterface
{
protected $entityManager;
protected $repository;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
$this->repository = $entityManager->getRepository(Author::class);
}
public function create(array $data = [])
{
return new Author();
}
public function getRepository(): EntityRepository
{
return $this->repository;
}
public function save($object): ManagerInterface
{
$this->entityManager->persist($object);
$this->entityManager->flush();
return $this;
}
}
Why my code coverage is 0% on AuthorDbManager?
Screen
The data in the DataProvider is collected before the actual tests start - and there is nothing useful being tested within the testInstances() method.
If you passed the classname and expected class into testInstances($methodName, $expectedClass):
public function testInstances(callable $method, $expectedClass)
{
$this->assertInstanceOf($expectedClass, $method());
}
The dataprovider could return a callable, and the expected result:
"create()" => [[$manager,'create'], Author::class],
then you'd at least be running the code with in the actual test. You may also be better to just pass back a string methodname - 'create', and run that with a locally created $manager instance - $manager->$method() in the test.
In general, it's best to test something as specific as you can - not just letting it convert to a true/false condition.
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);
}
}
I'm running phpunit tests on some classes and I get this error
Call to a member function getRepository() on null in
src/MyApp/MyBundle/CopyList.php on line 429
At that line is
$list = $this->em->getRepository('MyAppMyBundle:CopyList')->findByName($task);
from
namespace MyApp\MyBundle\Classes\Action;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
use MyApp\MyBundle\Entity\CopyVirtualList;
use Doctrine\ORM\EntityManager;
class CopyList extends Action
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function __clone() {
$task = $this->getTask();
$this->__copy($task);
}
public function __copy($task)
{
$list = $this->em->getRepository('MyAppMyBundle:CopyList')->findByName($task);
if (!$list) {
$list = new CopyVirtualList();
$this->em->persist($list);
$this->em->flush();
}
}
}
which is being called from the line
$clone = clone $container;
in
namespace tests\src\MyApp\MyBundle\Classes;
use Symfony\Component\HttpFoundation\Request;
abstract class TaskContextContainerTestCase extends TestCase
{
public function testCloning()
{
$container = $this->createInstance();
$container->setImmutable(true);
$this->assertTrue($container->isImmutable());
$clone = clone $container;
$this->assertNotEquals($container, $clone);
$this->assertFalse($clone->isImmutable());
}
protected function createInstance()
{
$task = $this->getMockBuilder('MyApp\MyBundle\Model\TaskContext')
->disableOriginalConstructor()
->getMockForAbstractClass();
$container = $task->createElement(
$this->getContainerKind(),
$this->getContainerType()
);
$container->setContext($task);
return $container;
}
}
TestCase is
namespace tests\src\MyApp\MyBundle;
use MyApp\Environment as Env;
require_once dirname(__DIR__) . '/../../../../app/AppKernel.php';
class TestCase extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
try {
$kernel = new \AppKernel('test', true);
$kernel->boot();
new \MyApp\Environment(); // init single env-instance
Env::getInstance()->setContainer($kernel->getContainer());
} catch (\Exception $e) {
}
parent::setUp();
}
}
And
namespace MyApp\MyBundle\Tests\Units\Classes\Action;
use MyApp\MyBundle\Classes\Action\CopyList;
use tests\src\MyApp\MyBundle\Classes\Action\ActionTestCase as TestCase;
class CopyListTest extends TestCase {
private $object;
public function setUp()
{
parent::setUp();
$task = $this->getMockBuilder('MyApp\MyBundle\Model\TaskContext')
->disableOriginalConstructor()
->getMock();
$this->object = new CopyList($task);
}
public function testCreateInstance() {
$task = $this->getMockBuilder('MyApp\MyBundle\Model\TaskContext')
->disableOriginalConstructor()
->getMockForAbstractClass();
$container = $task->createElement($this->getContainerKind(), $this->getContainerType());
$container->setContext($task);
return $container;
}
public function testCloning()
{
$container = $this->createInstance();
$container->setImmutable(true);
$this->assertTrue($container->isImmutable());
$clone = clone $container;
$this->assertNotEquals($container, $clone);
$this->assertFalse($clone->isImmutable());
}
}
Can anyone point me in the right direction?
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