Phpspec return bad value - symfony

I created register service and I want test that method. In the browser var_dump return true and phpspec return false.. Why ? Any Ideas?
Service : http://pastebin.com/9hYX7S14
Phpspec : http://pastebin.com/xm5NLYyG
Please help.

You need to stub (or mock) all your dependencies:
function it_check_user_exist_in_system(
Registry $doctrine,
ObjectRepository $repository,
User $user
)
{
$doctrine->getManager()->willReturn($doctrine);
$doctrine->getRepository('AcmeUserBundle:User')->willReturn($repository)
$repository->findOneBy(array('username'=>'user1'))->willReturn($user);
$this->checkUser('user1')->shouldReturn(true);
}

You're trying to get the result from a Mocked object.
You're best bet for testing this method is to test using a should be called assertion on the mocked object.
This is not a unit test its functional/acceptance test.

Related

Using swiftmailer in a repository class

I'm trying to send email in a repository class in symfony2 but I get this error:
Error:
Undefined method 'get'. The method name must start with either findBy or findOneBy!
the code is :
public function sendMail()
{
$message = \Swift_Message::newInstance()
->setSubject('Hello Email')
->setFrom('send#example.com')
->setTo('info#test.com')
->setBody("Salam dadash kheili khosh omadi");
$this->get('mailer')->send($message);
}
what should I change or do?
tnx
It's not good idea to do it from repository class. It should be moved to some service and called as an event or in the simplest way - from Controller. The repository class really do only database things.
In your case the issue is in $this->get('mailer'), because you are in repository you cannot access the containter. Move this part into controller class and everything will be all right.

Symfony 2 Service Error on unit Testing

I make some functional test with Symfony 2 and phpunit.
But i've some trouble with a Service.
Let me explain.
During my run test, i want to use some service used by the application. So i juste set my setUp function for setting the kernel :
static::$kernel = static::createKernel();
static::$kernel->boot();
$this->objectFactory = static::$kernel->getContainer()->get('some.application.objectfactory');
So i've this and in my function i need to used a service that return an object so i call my service like that
$var = $this->objectFactory->getObject($id);
and obviously in my tearDown function i just :
protected function tearDown()
{
$this->client->restart();
unset($this->client, $this->objectFactory);
}
So my problem is when i run a test i've this message :
Symfony\Component\DependencyInjection\Exception\InactiveScopeException: You cannot create a service ("request") of an inactive scope ("request").
And i can't find a way to solve this.
Did someone have any idea ??
My version of Symfony is 2.2.1 and my version of phpunit is 3.7.19
If someone can help me, i could be very happy.
I'm sorry if my English isn't so good.
EDIT
Maybe it could help someone, in the service i used that : :
$request = $this->container->get('request');
It seems to be the reason why it dosen't work, when i remove it, it doesn't say the error, but they still doesn't work.
EDIT
#Cyprian
According to you have change my code for what i want.
So i just add to my service, in the function that i want, the client (Client web test case), and then inside the function i just add this :
if (isset($client)) {
$request = $client->getRequest();
} else {
$request = $this->container->get('request');
}
So in my function where i call the service i've just this :
public function getObject($id)
{
//Get the service from the kernel
$service = static::$kernel->getContainer()->get('service');
$object = $service->getObject($id, $this->client);
}
and it works fine like this
#nifr
Your idea doesn't work for me, but i think your idea wasn't wrong, they just not works in my case
However Thanks for your help, i'm happy i works now, and i expect that post could help someone else
Try get request from the client, not service container:
$request = $this->client->getRequest();
In that way you can also get kernel and/or container:
$kernel = $this->client->getKernel();
$container = $this->client->getContainer();
One more useful tip: kernel from the client is rebooted between each two requests. So, for example if you pass your mock to client's container and do some request, in next request (after the first one) the container will not contain your mock.
There is no request available in phpUnit as long as you don't construct one.
If you want to test a request. create it like this:
use Symfony\Component\HttpFoundation\Request;
protected $request;
public function setUp()
{
// ...
$this->request = new Request();
// ... modify your request acccording to your needs
}
and add/call a setter in your Service using the request.
$service = $this->kernel->getContainer()->get('your_service')
$service->setRequest($this->request);
or create a Functional Test with WebtestCase.

Is it possible to mock our own service?

I want to mock a service that is required in a class constructor. I have an exception of PHPUnit : MyService is required, Mock_MyService_0afc7fc1 given.
But with the Request, EntityManager or other Symfony 2 component, I haven't this issue.
Here is my Class's construct :
use Acme\Bundle\Service\MyService;
use Symfony\Component\HttpFoundation\Request;
...
public function __construct(MyService $service, Request $request)
{
and my mock :
...
$service = $this->getMock('MyService');
$class = new Class($service, $request);
It's impossible to mock our own service ? Only Symfony 2 component ?
PS : If I delete MyServicelike that : public function __construct($service, Request $request), this works. But I want to define my variable with it :(
The issue is that PHPUnit at the time of the test execution can't find (or autoload) your MyService class.
That means that you'll probably run into the same issues with other Mocking libraries as all of them require the original class to exist to scan it and create the mock.
It happens because you need to tell PHPUnit the Fully-Qualified Class Name.
Change your code to $this->getMock("\Acme\Bundle\Service\MyService"); and it should work out.
(Still, give mockery a try. It's a nice library)

How to inject the #request into a service?

When I try to inject the #request into any of my services, I get this exception:
ScopeWideningInjectionException: Scope Widening Injection detected:
The definition "service.navigation" references the service "request"
which belongs to a narrower scope. Generally, it is safer to either
move "service.navigation" to scope "request" or alternatively rely on
the provider pattern by injecting the container itself, and requesting
the service "request" each time it is needed. In rare, special cases
however that might not be necessary, then you can set the reference to
strict=false to get rid of this error.
What is the best way to proceed? Should I try to set this strict=false and how, or should I NOT inject the request service, but rather pass it to the service through my controller each time I call functions I need?
Other possibility would be to inject the kernel and take it from there, but in my service I am using only #router and #request, so injecting the whole kernel would be irrational.
In Symfony 2.4, this has changed. Now, you can inject the 'request_stack' service.
For example:
use Symfony\Component\HttpFoundation\RequestStack;
class MyService
{
protected $request;
public function setRequest(RequestStack $request_stack)
{
$this->request = $request_stack->getCurrentRequest();
}
}
In your config.yml:
services:
my.service:
class: Acme\DemoBundle\MyService
calls:
- [setRequest, ["#request_stack"]]
Full documentation is here: http://symfony.com/blog/new-in-symfony-2-4-the-request-stack
I think there may have been some misunderstanding about what the official documentation says. In most cases you do want to inject the request directly with a scope="request" attribute on the service element. This makes the Scope Widening go away.
<service
id="zayso_core.openid.rpx"
class="Zayso\CoreBundle\Component\OpenidRpx" public="true" scope="request">
or in yml
zayso_core.openid.rpx:
class: Zayso\CoreBundle\Component\OpenidRpx
public: true
scope: request
It's only in specific special cases such as Twig extensions where you need to inject the container.
And kernel is not even mentioned in the page on scopes. Injecting the kernel is far worse (conceptually) than injecting a container.
UPDATE: For S2.4 and newer, use #Blowski's answer below.
NB: This answer was written back in 2012, when Symfony 2.0 was out and then it was the good way to do!
According to the official documentation it is usually not required to inject request into your services. In your service class you can pass kernel container (injecting it is not a big overhead, as it sounds), and then access request like this:
public function __construct(\AppKernel $kernel)
{
$this->kernel = $kernel;
}
public function getRequest()
{
if ($this->kernel->getContainer()->has('request')) {
$request = $this->kernel->getContainer()->get('request');
} else {
$request = Request::createFromGlobals();
}
return $request;
}
This code is also working fine when service is accessed in CLI (eg, during unit-testing).
The best way i found to make a service use the request service, not rely on the whole container and still not be required to have the request scope, was to make a RequestInjector service which takes the container. then you inject that into the service that wants to use the request object
class RequestInjector{
protected $container;
public function __construct(Container $container){
$this->container = $container;
}
public function getRequest(){
return $this->container->get('request');
}
}
class SomeService{
protected $requestInjector;
public function __construct(RequestInjector $requestInjector){
$this->requestInjector = $requestInjector;
}
}
for services.yml
request_injector:
class: RequestInjector
public: false
arguments: ['#service_container']
some_service:
class: SomeService
arguments: ['#request_injector']
The way I've found, and I'm sure it's probably not the best way (May not even be recommended), is to define the request service as synthetic.
Edit: Indeed, this is not recommended, because it disables the scope sanity checks.
This thread contains a good explanation of why Symfony is throwing that exception:
http://groups.google.com/group/symfony-devs/browse_thread/thread/a7207406c82ef07a/e2626c00f5cb9749
In your services.xml:
<service id="request" synthetic="true" />
<service id="my_service" class="......">
<argument type="service" id="request" />
</service>
Per the docs, it's better if you place your service in the request scope, or just inject the service container.
If you can't use RequestStack directly, you could create a factory service that returns the current request using RequestStack.
# services.yml
app.request:
class: Symfony\Component\HttpFoundation\RequestStack
factory: [ #request_stack, getCurrentRequest ]
Then you can access the current request using the app.request service.
another way to inject currentRequest directly:
setter injection:
calls:
- ['setRequest', ['#=service("request_stack").getCurrentRequest()']]
or constrauctor injection:
arguments:
$request: '#=service("request_stack").getCurrentRequest()'
I think it's more important to focus on getting the request instead of setting it. I would do something similar to #Blowski's solution, except using a getter. This is very similar to the documentation's example.
namespace Acme\HelloBundle\Newsletter;
use Symfony\Component\HttpFoundation\RequestStack;
class NewsletterManager
{
protected $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
protected function getRequest()
{
return $this->requestStack->getCurrentRequest();
}
public function foo()
{
$request = $this->getRequest();
// Do something with the request
}
}
And your services.yml config file.
services:
newsletter_manager:
class: Acme\HelloBundle\Newsletter\NewsletterManager
arguments: ["#request_stack"]
Now you're always sure that you're getting the correct request, and you don't have to worry about setting/re-setting the request.
As #simshaun states its best practice to place your service in the request scope. This makes the purpose of the service quite clear.
Note that this will make your service unavailable in other scopes such as the command line. However if your service relies upon the request, you should not be using it on the command line anyway (because there is no request available on the command line.

Extending phpunit error message

I want to add log output to all test messages.
$this->assertTrue(FALSE, "This assertion is False.". myLog::GetErrors());
I tried extending the PHPUnit_Framework_TestCase::assertThat function with my appended message, but it doesn't seem to have an effect on it. I know the extended PHPUnit_Framework_TestCase works because I have several helper functions (random string generation) in there as well that I use for testing.
Any other thoughts? Could it be a customer listener?
All of the assertions are static methods from PHPUnit_Framework_Assert and cannot be overridden by a subclass of TestCase. You can define your own assertions that call the originals with an amended message, however.
public static function assertTrue($value, $message='') {
PHPUnit_Framework_Assert::assertTrue($value, $message . myLog::GetErrors());
}
All failed tests call onNotSuccessfulTest() with the exception as the only parameter. You could override this method and in some cases add your log errors to the exception's message. Some of the PHPUnit exceptions provide a second description in addition to the error message contained in the exception.
public function onNotSuccessfulTest(Exception $e) {
if ($e instanceof PHPUnit_Framework_ExpectationFailedException) {
$e->setCustomMessage(implode(PHP_EOL,
array($e->getCustomMessage(), myLog::GetErrors())));
}
parent::onNotSuccessfulTest($e);
}
Update: As Gregory Lo noted in a comment below, setCustomMessage() and getCustomMessage() were removed in PHPUnit 3.6. :(
In recent PHPUnit Versions it is not necessary anymore.
When you specify the error parameter in an $this->assertXXXX() it preceeds PHPUnit's original message.
Screenshot:

Resources