sebastianbergmann / phpunit

The PHP Unit Testing framework.
https://phpunit.de/
BSD 3-Clause "New" or "Revised" License
19.71k stars 2.2k forks source link

returnValueMap only working when mocking stdClass #3501

Closed Canadadry closed 5 years ago

Canadadry commented 5 years ago
Q A
PHPUnit version 7.5.2
PHP version 7.2.1
Installation Method Composer

Edit:

I have read #1745 which give me the solution.

It seems that I am not the only one facing this issue. Maybe a bit more of information on the documentation could help other not loosing 3h. Something like : be carefull when mocking method with a default argument. You must add them in the map in order to work.

I have add at the end the solution.

Initial question:

I am trying to use returnValueMap starting with the doc example, I only change the class I am mocking from stdClass to Symfony\Component\DependencyInjection\ContainerInterface and it stop working, the call to the method now allways return null instead of content of the map.

Here the minimal code showing this error.

<?php
namespace Tests\SomeBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerInterface;
use PHPUnit\Framework\TestCase;

class SomeTest extends TestCase
{
    public function testReturnValueMapStub()
    {
        // Create a stub for the SomeClass class.
       //$stub = $this->getMockBuilder('stdClass')
       $stub = $this->getMockBuilder(ContainerInterface::class)
                        ->setMethods(['get','set','has','initialized','getParameter','hasParameter','setParameter'])
                        ->getMock();

        // Create a map of arguments to return values.
        $map = [
            ['a', 'd'],
            ['e', 'h']
        ];

        // Configure the stub.
        $stub->method('get')->will($this->returnValueMap($map));

        // $stub->doSomething() returns different values depending on
        // the provided arguments.
        $this->assertEquals('d', $stub->get('a'));
        $this->assertEquals('h', $stub->get('e'));
    }
}

You can comment/uncomment the two line calling getMockBuilder to see that the responsible is ContainerInterface.

Here the beginning the mapped interface

<?php
namespace Symfony\Component\DependencyInjection;

use Psr\Container\ContainerInterface as PsrContainerInterface;
interface ContainerInterface extends PsrContainerInterface
{
    const EXCEPTION_ON_INVALID_REFERENCE = 1;
    const NULL_ON_INVALID_REFERENCE = 2;
    const IGNORE_ON_INVALID_REFERENCE = 3;
    const IGNORE_ON_UNINITIALIZED_REFERENCE = 4;

    public function set($id, $service);

    public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);

...

The code working

The issue was : the get need 2 arguments and the second one is facultative, so easily forgotten. It is required to put it on the map. It was working with stdClass because php had no idea this method required 2 arguments. Using the interface it know and map the first two element of the map has method argument, thus nothing is left to be return.

    public function testReturnValueMapStub()
    {
        // Create a stub for the SomeClass class.
       //$stub = $this->getMockBuilder('stdClass')
       $stub = $this->getMockBuilder(ContainerInterface::class)
                        ->setMethods(['get','set','has','initialized','getParameter','hasParameter','setParameter'])
                        ->getMock();

        // Create a map of arguments to return values. with default argument 
        $map = [
            ['a','c', 'd'],
            ['e','d','h']
        ];

        // Configure the stub.
        $stub->method('get')->will($this->returnValueMap($map));

        // $stub->doSomething() returns different values depending on
        // the provided arguments.
        $this->assertEquals('d', $stub->get('a','c'));
        $this->assertEquals('h', $stub->get('e','d'));
    }

Return of command composer info | sort

composer/ca-bundle                   1.1.3    Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bu...
doctrine/annotations                 v1.6.0   Docblock Annotations Parser
doctrine/cache                       v1.8.0   Caching library offering an object-oriented API for many cache backends
doctrine/collections                 v1.5.0   Collections Abstraction library
doctrine/common                      v2.10.0  PHP Doctrine Common project is a library that provides additional functionality that other...
doctrine/data-fixtures               v1.3.1   Data Fixtures for all Doctrine Object Managers
doctrine/dbal                        v2.9.2   Powerful PHP database abstraction layer (DBAL) with many features for database schema intr...
doctrine/doctrine-bundle             1.10.1   Symfony DoctrineBundle
doctrine/doctrine-cache-bundle       1.3.5    Symfony Bundle for Doctrine Cache
doctrine/doctrine-fixtures-bundle    v2.4.1   Symfony DoctrineFixturesBundle
doctrine/event-manager               v1.0.0   Doctrine Event Manager component
doctrine/inflector                   v1.3.0   Common String Manipulations with regard to casing and singular/plural rules.
doctrine/instantiator                1.1.0    A small, lightweight utility to instantiate objects in PHP without invoking their construc...
doctrine/lexer                       v1.0.1   Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
doctrine/orm                         v2.6.3   Object-Relational-Mapper for PHP
doctrine/persistence                 v1.1.0   The Doctrine Persistence project is a set of shared interfaces and functionality that the ...
doctrine/reflection                  v1.0.0   Doctrine Reflection component
fig/link-util                        1.0.0    Common utility implementations for HTTP links
incenteev/composer-parameter-handler v2.1.3   Composer script handling your ignored parameter file
jdorn/sql-formatter                  v1.2.17  a PHP SQL highlighting library
jms/metadata                         1.7.0    Class/method/property metadata management in PHP
jms/parser-lib                       1.0.0    A library for easily creating recursive-descent parsers.
jms/serializer                       1.13.0   Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.
jms/serializer-bundle                2.4.3    Allows you to easily serialize, and deserialize data of any complexity
monolog/monolog                      1.24.0   Sends your logs to files, sockets, inboxes, databases and various web services
myclabs/deep-copy                    1.8.1    Create deep copies (clones) of your objects
openlss/lib-array2xml                0.0.10   Array2XML conversion library credit to lalit.org
paragonie/random_compat              v9.99.99 PHP 5.x polyfill for random_bytes() and random_int() from PHP 7
phar-io/manifest                     1.0.3    Component for reading phar.io manifest information from a PHP Archive (PHAR)
phar-io/version                      2.0.1    Library for handling version information and constraints
phpcollection/phpcollection          0.5.0    General-Purpose Collection Library for PHP
phpdocumentor/reflection-common      1.0.1    Common reflection classes used by phpdocumentor to reflect the code structure
phpdocumentor/reflection-docblock    4.3.0    With this component, a library can provide support for annotations via DocBlocks or otherw...
phpdocumentor/type-resolver          0.4.0    
phpoption/phpoption                  1.5.0    Option Type for PHP
phpspec/prophecy                     1.8.0    Highly opinionated mocking framework for PHP 5.3+
phpunit/php-code-coverage            6.1.4    Library that provides collection, processing, and rendering functionality for PHP code cov...
phpunit/php-file-iterator            2.0.2    FilterIterator implementation that filters files based on a list of suffixes.
phpunit/php-text-template            1.2.1    Simple template engine.
phpunit/php-timer                    2.0.0    Utility class for timing
phpunit/php-token-stream             3.0.1    Wrapper around PHP's tokenizer extension.
phpunit/phpunit                      7.5.2    The PHP Unit Testing framework.
psr/cache                            1.0.1    Common interface for caching libraries
psr/container                        1.0.0    Common Container Interface (PHP FIG PSR-11)
psr/link                             1.0.0    Common interfaces for HTTP links
psr/log                              1.1.0    Common interface for logging libraries
psr/simple-cache                     1.0.1    Common interfaces for simple cachingas Doctrine field type.
sebastian/code-unit-reverse-lookup   1.0.1    Looks up which function or method a line of code belongs to
sebastian/comparator                 3.0.2    Provides the functionality to compare PHP values for equality
sebastian/diff                       3.0.1    Diff implementation
sebastian/environment                4.0.1    Provides functionality to handle HHVM/PHP environments
sebastian/exporter                   3.1.0    Provides the functionality to export PHP variables for visualization
sebastian/global-state               2.0.0    Snapshotting of global state
sebastian/object-enumerator          3.0.3    Traverses array structures and object graphs to enumerate all referenced objects
sebastian/object-reflector           1.1.1    Allows reflection of object attributes, including inherited and non-public ones
sebastian/recursion-context          3.0.0    Provides functionality to recursively process PHP variables
sebastian/resource-operations        2.0.1    Provides a list of PHP built-in functions that operate on resources
sebastian/version                    2.0.1    Library that helps with managing the version number of Git-hosted PHP projects
sensio/distribution-bundle           v5.0.24  Base bundle for Symfony Distributions
sensio/framework-extra-bundle        v5.2.4   This bundle provides a way to configure your controllers with annotations
sensio/generator-bundle              v3.1.7   This bundle generates code for you
sensiolabs/security-checker          v5.0.3   A security checker for your composer.lock
swiftmailer/swiftmailer              v5.4.12  Swiftmailer, free feature-rich PHP mailer
symfony/monolog-bundle               v3.3.1   Symfony MonologBundle
symfony/phpunit-bridge               v3.4.21  Symfony PHPUnit Bridge
symfony/polyfill-apcu                v1.10.0  Symfony polyfill backporting apcu_* functions to lower PHP versions
symfony/polyfill-ctype               v1.10.0  Symfony polyfill for ctype functions
symfony/polyfill-intl-icu            v1.10.0  Symfony polyfill for intl's ICU-related data and classes
symfony/polyfill-mbstring            v1.10.0  Symfony polyfill for the Mbstring extension
symfony/polyfill-php56               v1.10.0  Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions
symfony/polyfill-php70               v1.10.0  Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions
symfony/polyfill-util                v1.10.0  Symfony utilities for portability of PHP codes
symfony/swiftmailer-bundle           v2.6.7   Symfony SwiftmailerBundle
symfony/symfony                      v3.4.21  The Symfony PHP framework
theseer/tokenizer                    1.1.0    A small library for converting tokenized PHP source code into XML and potentially other fo...
twig/twig                            v2.6.2   Twig, the flexible, fast, and secure template language for PHP
webmozart/assert                     1.4.0    Assertions to validate method input/output with nice error messages.
Canadadry commented 5 years ago

I have updated my comment with the solution.