Asked  9 Months ago    Answers:  5   Viewed   51 times

I'm currently working on an open source bundle for Symfony2, and really want it to be the dogs nadgers in terms of unit test coverage and general reliability, however I've run into a snag due to my lack of PHPUnit knowledge (or a complex scenario, who knows)..

At present, I have a Mailer class, for handling individual mail scenarios. It looks a bit like this:

<?php
use SymfonyBundleFrameworkBundleTemplatingEngineInterface;
use SymfonyComponentRoutingRouterInterface;

class Mailer
{
    protected $mailer;
    protected $router;
    protected $templating;
    protected $parameters;

    public function __construct($mailer, RouterInterface $router, EngineInterface $templating, array $parameters)
    {
        $this->mailer = $mailer;
        $this->router = $router;
        $this->templating = $templating;
        $this->parameters = $parameters;
    }
}

Simple enough, got some Symfony2 interface gubbins in there to handle different routing and templating systems, happy happy joy joy.

Here's the initial test I tried setting up for the above:

<?php
use MyBundleMailerMailer

class MailerTest extends PHPUnit_Framework_TestCase
{
    public function testConstructMailer
    {
        $systemMailer = $this->getSystemMailer();
        $router = $this->getRouter();
        $templatingEngine = $this->getTemplatingEngine();

        $mailer = new Mailer($systemMailer, $router, $templatingEngine, array());
    }

    protected function getSystemMailer()
    {
        $this->getMock('SystemMailer', array('send');
    }   
    protected function getRouter()
    {
        $this->getMock('RouterInterface', array('generate');
    }

    protected function getTemplatingEngine()
    {
        $this->getMock('RouterInterface', array('render');
    }
}

The problem here is that my mock objects do not implement SymfonyBundleFrameworkBundleTemplatingEngineInterface and SymfonyComponentRoutingRouterInterface, so I can't use any mock objects that I create myself. One method I have tried is creating an abstract class which implements the correct interface on the test page, however the getMockForAbstractClass fails, stating it can't find the class...

 Answers

68

When mocking you need to use the full qualified class path as the mock functionality is not taking the namespace of the calling code or any "use" statements into consideration.

Try

->getMock('\Symfony\Component\Routing\RouterInterface'); 

and leave out the second parameter. Usually specifying the methods does a lot more worse than good. Only if you want all the other methods to work like before than you should need the second parameter.

Example

<?php

namespace bar;

class MyClass {}

namespace foo;

use barMyClass;

class MockingTest extends PHPUnit_Framework_TestCase {

    public function testMock() {
        var_dump($this->getMock('MyClass') instanceOf MyClass);
        var_dump($this->getMock('\bar\MyClass') instanceOf MyClass);
    }   
}

Produces:

/phpunit.sh --debug fiddleTestThree.php 
PHPUnit @package_version@ by Sebastian Bergmann.


Starting test 'fooMockingTest::testMock'.
.bool(false)
bool(true)
Wednesday, March 31, 2021
 
Angolao
answered 9 Months ago
23

I execute the test of the other vendor of my project with this configuration:

/app/phpunit.xml.dist

<testsuites>
    <testsuite name="Project Test Suite">
        <directory>../vendor/vendorname/vendor-catalog-bundle/Acme/DemoCatalogBundle/Tests/Entity</directory>
        <directory>../src/*/*Bundle/Tests</directory>
        <directory>../src/*/Bundle/*Bundle/Tests</directory>
        <directory>../vendor/vendorname/acme-validator-bundle/Acme/DemoBundle/Tests</directory>
    </testsuite>
</testsuites>

Hope this help

Wednesday, March 31, 2021
 
Zulakis
answered 9 Months ago
39

After some searching I found the answer here on stackoverflow.

The symfony2 crawler, by default, guesses that the location of server is at "localhost". Yet mine is not there. So I had to tell the crawler where to look.

This is the code I had to add 'HTTP_HOST' => 'my.server.location'

Adding this code makes the code look like this:

$this->client = static::createClient( 
     array(),
     array(
        'HTTP_HOST' => 'my.server.location', //dependent on server        
    ));
$this->client->followRedirects(true);

So now when I get the url $crawler = $client->request('GET', '/admin/login');, The crawler will get the following url: http://my.server.location/admin/login.

Hope this helps anyone!

And credits to Matt for the answer

Saturday, May 29, 2021
 
ranhan
answered 7 Months ago
65

You need to put any strings starting with @ in quotes:

arguments:
    ["@security.context", "@fos_user.user_manager"]

Reserved characters, like @, should be quoted. Unquoted @s were deprecated in Symfony 2.8. Symfony 3.0 will forbid you to use such definitions and will throw an exception.

If you don't have control over the bundle that registered the problematic configuration, send a pull request with a fix to the vendor. As a quick fix you can downgrade Symfony. 2.7 will work, as well as 2.8 (the later will only emit a deprecation notice).

Saturday, May 29, 2021
 
FWH
answered 7 Months ago
FWH
38

In my case the answer turned out to be quite simple:

$this->expects($this->at(0))
    ->method('write')
    ->with(/* first set of params */);

$this->expects($this->at(1))
    ->method('write')
    ->with(/* second set of params */);

The key is to use $this->at(n), with n being the Nth call of the method. I couldn't do anything with any of the logicalOr() variants I tried.

Sunday, August 1, 2021
 
cegfault
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share