Git Product home page Git Product logo

mockery / mockery Goto Github PK

View Code? Open in Web Editor NEW
10.6K 73.0 458.0 36.33 MB

Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL).

Home Page: http://docs.mockery.io/en/stable/

License: BSD 3-Clause "New" or "Revised" License

PHP 99.91% Makefile 0.03% Shell 0.05%
mockery phpunit php stub mock mocking test-doubles

mockery's Introduction

Mockery

Build Status Supported PHP Version Code Coverage Type Coverage Latest Stable Version Total Downloads

Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.

Mockery is released under a New BSD License.

Installation

To install Mockery, run the command below and you will get the latest version

composer require --dev mockery/mockery

Documentation

In older versions, this README file was the documentation for Mockery. Over time we have improved this, and have created an extensive documentation for you. Please use this README file as a starting point for Mockery, but do read the documentation to learn how to use Mockery.

The current version can be seen at docs.mockery.io.

PHPUnit Integration

Mockery ships with some helpers if you are using PHPUnit. You can extend the Mockery\Adapter\Phpunit\MockeryTestCase class instead of PHPUnit\Framework\TestCase, or if you are already using a custom base class for your tests, take a look at the traits available in the Mockery\Adapter\Phpunit namespace.

Test Doubles

Test doubles (often called mocks) simulate the behaviour of real objects. They are commonly utilised to offer test isolation, to stand in for objects which do not yet exist, or to allow for the exploratory design of class APIs without requiring actual implementation up front.

The benefits of a test double framework are to allow for the flexible generation and configuration of test doubles. They allow the setting of expected method calls and/or return values using a flexible API which is capable of capturing every possible real object behaviour in way that is stated as close as possible to a natural language description. Use the Mockery::mock method to create a test double.

$double = Mockery::mock();

If you need Mockery to create a test double to satisfy a particular type hint, you can pass the type to the mock method.

class Book {}

interface BookRepository {
    function find($id): Book;
    function findAll(): array;
    function add(Book $book): void;
}

$double = Mockery::mock(BookRepository::class);

A detailed explanation of creating and working with test doubles is given in the documentation, Creating test doubles section.

Method Stubs 🎫

A method stub is a mechanism for having your test double return canned responses to certain method calls. With stubs, you don't care how many times, if at all, the method is called. Stubs are used to provide indirect input to the system under test.

$double->allows()->find(123)->andReturns(new Book());

$book = $double->find(123);

If you have used Mockery before, you might see something new in the example above β€” we created a method stub using allows, instead of the "old" shouldReceive syntax. This is a new feature of Mockery v1, but fear not, the trusty ol' shouldReceive is still here.

For new users of Mockery, the above example can also be written as:

$double->shouldReceive('find')->with(123)->andReturn(new Book());
$book = $double->find(123);

If your stub doesn't require specific arguments, you can also use this shortcut for setting up multiple calls at once:

$double->allows([
    "findAll" => [new Book(), new Book()],
]);

or

$double->shouldReceive('findAll')
    ->andReturn([new Book(), new Book()]);

You can also use this shortcut, which creates a double and sets up some stubs in one call:

$double = Mockery::mock(BookRepository::class, [
    "findAll" => [new Book(), new Book()],
]);

Method Call Expectations πŸ“²

A Method call expectation is a mechanism to allow you to verify that a particular method has been called. You can specify the parameters and you can also specify how many times you expect it to be called. Method call expectations are used to verify indirect output of the system under test.

$book = new Book();

$double = Mockery::mock(BookRepository::class);
$double->expects()->add($book);

During the test, Mockery accept calls to the add method as prescribed. After you have finished exercising the system under test, you need to tell Mockery to check that the method was called as expected, using the Mockery::close method. One way to do that is to add it to your tearDown method in PHPUnit.

public function tearDown()
{
    Mockery::close();
}

The expects() method automatically sets up an expectation that the method call (and matching parameters) is called once and once only. You can choose to change this if you are expecting more calls.

$double->expects()->add($book)->twice();

If you have used Mockery before, you might see something new in the example above β€” we created a method expectation using expects, instead of the "old" shouldReceive syntax. This is a new feature of Mockery v1, but same as with allows in the previous section, it can be written in the "old" style.

For new users of Mockery, the above example can also be written as:

$double->shouldReceive('find')
    ->with(123)
    ->once()
    ->andReturn(new Book());
$book = $double->find(123);

A detailed explanation of declaring expectations on method calls, please read the documentation, the Expectation declarations section. After that, you can also learn about the new allows and expects methods in the Alternative shouldReceive syntax section.

It is worth mentioning that one way of setting up expectations is no better or worse than the other. Under the hood, allows and expects are doing the same thing as shouldReceive, at times in "less words", and as such it comes to a personal preference of the programmer which way to use.

Test Spies πŸ•΅οΈ

By default, all test doubles created with the Mockery::mock method will only accept calls that they have been configured to allow or expect (or in other words, calls that they shouldReceive). Sometimes we don't necessarily care about all of the calls that are going to be made to an object. To facilitate this, we can tell Mockery to ignore any calls it has not been told to expect or allow. To do so, we can tell a test double shouldIgnoreMissing, or we can create the double using the Mocker::spy shortcut.

// $double = Mockery::mock()->shouldIgnoreMissing();
$double = Mockery::spy();

$double->foo(); // null
$double->bar(); // null

Further to this, sometimes we want to have the object accept any call during the test execution and then verify the calls afterwards. For these purposes, we need our test double to act as a Spy. All mockery test doubles record the calls that are made to them for verification afterwards by default:

$double->baz(123);

$double->shouldHaveReceived()->baz(123); // null
$double->shouldHaveReceived()->baz(12345); // Uncaught Exception Mockery\Exception\InvalidCountException...

Please refer to the Spies section of the documentation to learn more about the spies.

Utilities πŸ”Œ

Global Helpers

Mockery ships with a handful of global helper methods, you just need to ask Mockery to declare them.

Mockery::globalHelpers();

$mock = mock(Some::class);
$spy = spy(Some::class);

$spy->shouldHaveReceived()
    ->foo(anyArgs());

All of the global helpers are wrapped in a !function_exists call to avoid conflicts. So if you already have a global function called spy, Mockery will silently skip the declaring its own spy function.

Testing Traits

As Mockery ships with code generation capabilities, it was trivial to add functionality allowing users to create objects on the fly that use particular traits. Any abstract methods defined by the trait will be created and can have expectations or stubs configured like normal Test Doubles.

trait Foo {
    function foo() {
        return $this->doFoo();
    }

    abstract function doFoo();
}

$double = Mockery::mock(Foo::class);
$double->allows()->doFoo()->andReturns(123);
$double->foo(); // int(123)

Versioning

The Mockery team attempts to adhere to Semantic Versioning, however, some of Mockery's internals are considered private and will be open to change at any time. Just because a class isn't final, or a method isn't marked private, does not mean it constitutes part of the API we guarantee under the versioning scheme.

Alternative Runtimes

Mockery 1.3 was the last version to support HHVM 3 and PHP 5. There is no support for HHVM 4+.

A new home for Mockery

⚠️️ Update your remotes! Mockery has transferred to a new location. While it was once at padraic/mockery, it is now at mockery/mockery. While your existing repositories will redirect transparently for any operations, take some time to transition to the new URL.

$ git remote set-url upstream https://github.com/mockery/mockery.git

Replace upstream with the name of the remote you use locally; upstream is commonly used but you may be using something else. Run git remote -v to see what you're actually using.

mockery's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mockery's Issues

Mocking Zend_Soap_Client calls

Hi,

I'd like to know what would be the best way to mock magic method calls. Since in the README.md is not very clear how to do this kind of stuff, I think an example could help.

Here is an example code, very close to what I have in my code base.

https://gist.github.com/2027570

When this test suite is executed, the message thrown is

1) MagicMethodsTest::testSomeCall
Mockery\Exception: No matching handler found for Zend_Soap_Client::soapCall("param1", "param2"). Either the method was unexpected or its arguments matched no expected argument list for this method

Regards and thanks in advance!
Christian.

Forward Blocking

Hello Padraic,

Thanks for a helpful library. It's been very useful for my unit testing endeavors.

I frequently need to stub functions that are called within the scope of the class that I am testing. This following instructions explain the problem and how SimpleTest supports this flexibility.

http://simpletest.sourceforge.net/en/partial_mocks_documentation.html#inject

I could not find a way to mock an object with Mockery to achieve the same solution. Assuming that it is not possible, I forked the project and added this flexibility. It's a simple implementation that works for me. I welcome your comments if you have a chance to review.

http://github.com/bwittenberg/mockery

Calling a mocked protected method from a non-mocked method fails

I have partially mocked class with a mocked protected method and a non-mocked public method calling the mocked method. Instead of returning the mocked method the original protected method is called.

Testcase:

<?php
class ContainerTest extends PHPUnit_Framework_TestCase
{

    public function setup ()
    {
        $this->container = new \Mockery\Container;
    }

    public function teardown()
    {
        $this->container->mockery_close();
    }

    /**
     * @group partial
     */
    public function testCanPartiallyMockAClassWithPublicMethodCallingMockedProtectedMethod()
    {
        $m = $this->container->mock('MockeryTest_PartialNormal[foo]');
        $this->assertTrue($m instanceof MockeryTest_PartialNormal);
        $m->shouldReceive('foo')->andReturn('cba');
        $this->assertEquals('cba', $m->foo());
        $this->assertEquals('cba', $m->bar());
    }
}


class MockeryTest_PartialNormal {
    protected function foo() {return 'abc';}
    public function bar() {return $this->foo();}
}

Output:

1) ContainerTest::testCanPartiallyMockAClassWithPublicMethodCallingMockedProtectedMethod
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-cba
+abc

The last assertion in the test fails. Changing the visibilty of the method 'foo' to public fixes the test.

Missing 0.7.1 tag

In the README you say the latest stable version is 0.7.1; but there's no 0.7.1 tag, just 0.7.0.

Creating an instance of Mock of non-loaded class

I want to create a mock of a specific type of class, but it isn't loaded (and I don't want to load it [the class isn't in my repository]). There doesn't seem to be any way to create a new mock class with an arbitrary type to pass into typehint parameters.

can't mock classes exposing a __call method

When you try to mock a class that expose a __call method, you get a Cannot redeclare __call" fatal error, because mockery redefines every method of the mocked class in the mock body, thus conflicting with mockery's own __call.

Not sure what's the best way to deal with that. I guess plain removing the original __call would work, given the nature of what we're doing there (in which case you should remove the typehint in MockInterface::__call's signature).

Just a thanks

The more I work with mockery the cooler I find it. I think it's a brilliant piece of software! Thanks for it!

Feature request: Nice fluent interfaces

I often find myself writing a lot of:

$mockIterator = m::mock('SomeClass')
$mockIterator    ->shouldReceive('rewind')
                   ->andReturn($mockIterator)
                 ->shouldReceive('next')
                   ->andReturn($mockIterator)
                 ->shouldReceive('valid')
                   ->andReturn(false)
                 ->shouldReceive('current')
                   ->andThrow('SomeException')
                 ->mock();

As much as I love it, notice I have to instantiate the object - and then use it again to return itself - which seems a bit of a hack to be honest.
I think it could be a lot nicer if we could have something like this perhaps:

$mockIterator = m::mock('SomeClass')
                 ->shouldReceive('rewind')
                   ->andReturn(m::this())
                 ->shouldReceive('next')
                   ->andReturn(m::this())
                 ->shouldReceive('valid')
                   ->andReturn(false)
                 ->shouldReceive('current')
                   ->andThrow('SomeException')
                 ->mock();

or even:

$mockIterator = m::mock('SomeClass')
                 ->shouldReceive('rewind', 'next', 'someOtherFluentMethod')
                   ->andReturn(m::this())
                 ->shouldReceive('valid')
                   ->andReturn(false)
                 ->shouldReceive('current')
                   ->andThrow('SomeException')
                 ->mock();

ContainerTest::testCanMockSpl fails

Hello!

When running Mockery unit tests, one of the tests - ContainerTest::testCanMockSpl - fails with:

"Mockery\Exception: The method _bad_state_ex is marked final and it is not possible to generate a mock object with such a method defined. You should instead pass an instance of this object to Mockery to create a partial mock."

Running PHP 5.3.9. on Fedora 16.

Proxying Objects -Another Gotcha

Came across this style of code. Proxying an object that is used in a 'method_exists' call breaks the code as the method is not defined on the proxy object. A simple but not so straight forward answer would be to change all the code to use type hinting.

class AClass
{
    public function aMethod()
    {
        return 3;
    }
}

class BClass
{
    public function __construct($aClass) {
        if (!$aClass || !is_object($aClass) || !method_exists($aClass, "aMethod")) {
            throw new Exception("Invalid AClass object passed to ".__METHOD__);
        }
    // ...
    }
}

$stubAClass = \Mockery::mock('overload:AClass', array('aMethod' => null));
$bClass = new BClass($stubAClass);

"No matching handler" more verbose?

I often get this error:

Mockery\Exception: No matching handler found for Mongo_Collection::updateArray(Array, Array). Either the method was unexpected or its arguments matched no expected argument list for this method

Is there an option (and if not, could there be) to say something like:

Received: array('foo'), array('bar')
Expected: array('baz'), array('bat') or
array('bat'), array('quux')

perhaps in a PHPUnit kind of way (i.e. array diffs)?

It's all very well when you know you've got the wrong array but it will help miles distinguishing what's supposed to happen and what does happen.

Remember mock configuration for new instances

I'm currently developing a component that uses FQNs during runtime, so my mocks need to have a specific namespace and class name that I need to test. I've tried to class_alias the generated mock, but found out that instantiating the mock class again doesn't keep the expectations i've set up before.

Sample:

<?php
$foo = Mockery::mock('stdClass');
$foo->shouldReceive('bar')->andReturn('baz');
var_dump($foo->bar()); //string(3) "baz"
$mockClass = get_class($foo);
class_alias($mockClass, 'MyNamespace\MyClass');
$foo2 = new \MyNamespace\MyClass;
var_dump($foo2->bar()); //BadMethodCallException: Method ::bar() does not exist on this mock object
$foo3 = new $mockClass; 
var_dump($foo3->bar()); //BadMethodCallException: Method ::bar() does not exist on this mock object

Expected number of calls methods fail (for me)

This is a method from a suite I'm currently writing.

It tests that given a keyword and a number of tweets desired that the correct URL is generated to make a call to the Twitter search API.

The problem I have is that despite specifying that that methods should only be called once they can be called multiple times and the expectation does not fail.

This happens on all expected number of call arguments I've tried. You can see all my tests at https://github.com/benwaine/TwitterSearch/tree/master/tests. They are a bit scrappy at the moment - it's my first run through!

Thanks for your help.

public function testGetTweetsCorrectUri() {
    $mockHttp = m::mock('\Zend_Http_Client');

    $mockHttp->shouldReceive('setUri')
             ->with('http://search.twitter.com/search.json?q=microsoft&page=1&rpp=100')
             ->once();

    $mockHttp->shouldReceive('request')
            ->once();

    $mockHttpResp = m::mock("\Zend_Http_Response");
    $mockHttpResp->shouldReceive('getBody')
                 ->andReturn(Helper\TweetProvider::getFixture('ClientTest-BasicTweets'));

    $mockHttp->shouldReceive('getLastResponse')
             ->withNoArgs()
             ->once()
             ->andReturn($mockHttpResp);

    $client = new Client($mockHttp);

    $tweets = $client->getTweets(array('microsoft'), 2);

}

\Mockery::close() does not run verification tasks

README states that call to \Mockery::close() "cleans up the Mockery container used by the current test, and run any verification tasks needed for your expectations", but only the first part is true (cleaning up).

Current implementation of \Mockery::close() invokes \Mockery\Container::mockery_close() which shuts down all mocks and removes them.
If I expect a method call 4 times, but it was called 0, 1, 2, 3 or 5+ times, \Mockery\CountValidator\Exception won't be thrown and test will pass when it shouldn't.

\Mockery::close() should first call \Mockery\Container::mockery_teardown() and then \Mockery\Container::mockery_close(). Exception will be thrown and test will fail.
But...
If \Mockery::close() was called at the end of a test (or in tearDown()) \PHPUnit_Framework_TestResult will be notified of exception and testing will proceed.
If \Mockery::close() was called in \Mockery\Adapter\Phpunit\TestListener::endTest(), exception won't be catched and attributed to currently running test, so PHP will issue fatal error.

Scalar type-hints on partial mocks throws exception

It took me a little while to figure out why I was getting the following error when creating a partial mock of a non-abstract class:

ReflectionException: Class bool does not exist
#0 /path/to/Mockery/Generator.php(239): ReflectionParameter->getClass()
#1 /path/to/Mockery/Generator.php(209): Mockery\Generator::_renderPublicMethodParameters(Object(ReflectionMethod))

It turns out this was being caused by the following method declaration, which, for some reason, is valid despite being completely pointless:

public function setHaltOnFailure( bool $haltOnFailure )

I'm not sure if this issue applies to anything other than partial mocks as I haven't come across any yet.

Mocking Redis fails

Hi,

Mocking the latest PHPRedis fails with the following errors:

https://gist.github.com/2708742

Being a pecl class, I assumed it would be difficult but not quite this difficult.

This is using the Mockery 0.7.2 tag and the latest commit from PHPRedis:
56015f13d7230a0c699e67dac756cdc4557d263b

Regards
Dan

Regular mocks don't pass instanceof

I noticed a difference to phpUnit mocks which I would call a disadvantage. If I create a regular mock with the name of an existing class but not as an alias or instance mock,

$mock = m::mock('NameOfExistingClass');

... the mock does not pass instanceof because it is an instance of Mockery. If I use the phpUnit getMock with the same class name,

$this->getMock('NameOfExistingClass');

that mock instance passes instanceof because the name is wrapped like so: Mock_NameOfExistingClass_somethingsomething.

It would be a great improvement, if Mockery would act in the same way.
You may now answer that this is what alias mocks are for but there is a scenario where I can't use alias mocks because and instance of that class is being created as a dependency of the tested class and I just need my mock to pass instanceof.

Mock support for static classes

Mockery doesn't seem to support mocking static classes.

This could be achieved using __callStatic and the mock creation method described in #6

When creating a second mock object with the same name, fatal error occurs.

First, let me say I'm playing around with Mockery right now, and I really like the prospects. If I find the time I'd like to contribute to this project.

Now, to the issue I've run into: when creating a mock object a second time with the same name in a separate method in my test case, I get the following exception:
Fatal error: Cannot redeclare Mockery_4b00d47720612::shouldReceive() in D:\Path\To\Mockery.php(104) : eval()'d code on line 1

Code:
class MockeryInUnitTest extends PHPUnit_Framework_TestCase {
public function testFoo() {
$mockObject = mockery('MockObject');
}

  public function testBar() {
    $mockObject = mockery('MockObject');
  }
}

It looks like I need to manually destroy the reference to the mock object somehow, but didn't see a way to do so. I haven't really searched long and hard for a means to destroy a reference to a class that has been created through reflection, but think that that might be a more complicated solution to this problem.

Probably just checking to see if the shouldReceive method has already been declared might be enough.

Great project, please keep it up!

Addition for the readme

More and more people configure their testsuites via phpunit.xml.
How would you register the listener there?

I figure something like that should work:

<listeners>
    <listener class="TestListener" file="Mockery/Adapter/Phpunit/TestListener.php"></listener>
</listeners>

Could you add that to your documentation?

Partial mocking with multiple mocked methods

Hi!

Got some more bugs tested out.
As stated in the docs you can do partial mocking by defining mocked methods in square brackets like in the example:

$mock = \Mockery::mock('MyNamespace\MyClass[foo,bar]');

That in fact doesn't work and throws an exception like the following:

Mockery\Exception: Class name follows the format for defining multiple interfaces, however one or more of the interfaces do not exist or are not included, or the base class (optional) does not exist

Here I composed a test class:
class Test_Partials
{

public function methodOne()
{
}

public function methodTwo()
{
}

}

And a testcase for it:
class Test_PartialsTest extends Shift_Test_Case
{

public function setUp()
{
    parent::setUp();
    $this->appBootstrap();
}

public function testCanCreateMock()
{
    $partialMock = Mockery::mock('Test_Partials');
    $this->assertType('Test_Partials', $partialMock);
}

public function testCanCreatePartialMockWithOneMockedMethod()
{
    $partialMock = Mockery::mock('Test_Partials[methodOne]');
    $this->assertType('Test_Partials', $partialMock);
}

public function testCantCreatePartialMockWithTwoMockedMethods()
{
    $partialMock = Mockery::mock('Test_Partials[methodOne,methodTwo]');
    $this->assertType('Test_Partials', $partialMock);
}

}

And again please excuse the markdown.
Dmitry.

preg_match warning thrown if xdebug.scream=1

Hello!

If one has xdebug.scream turned on, preg_match in some cases can throw a warning.

A test for this can be found at robertbasic@d9d8dfa

Now, I know that I'm expecting "bar" and "baz" there, and providing "spam" and "ham" instead, but, the problem is that the preg_match warning masks the real error: "Mockery\Exception: No matching handler found for ...", which produces a lot of head-scratching to figure out what is going on.

The offending preg_match is in Mockery\Expectation::_matchArg, around line 278.

Abstract class with __call method

I just tried mocking Zend\Mvc\Controller\ActionController from ZF2 and ran into the following issue. I don't actually need to mock any methods, I just want an instance of an Abstract class. The problem is, if I do:

$this->controller = \Mockery::mock('Zend\Mvc\Controller\ActionController[]');

I get:

Declaration of Mockery_4fd0dcab00dda::__call() should be compatible with that of Zend\Mvc\Controller\ActionController::__call()

The only way to avoid this is to ask it to mock the __call method:

$this->controller = \Mockery::mock('Zend\Mvc\Controller\ActionController[__call]');

Is this correct or really an issue? I think the fix would be in Mockery\Generator::applyMockeryTo to always check for the __call method...not sure what is desired though.

Problem with multiple Demeter chains?

Hello,
i'm having problems with multiple demeter-chain expectations on a mock.

$contextMock = m::mock('\My\Object\Interface);
$contextMock->shouldReceive('getToken->getUser->getCustomers->count')->andReturn(0);
$contextMock->shouldReceive('getToken->getUser->getProfileData->getContactName')->andReturn('foo');

The code i'm trying to test is the following:

public function doSomething() {
    $user = $myObject->getToken()->getUser()->getCustomers()->count();
    $name = $myObject->getToken()->getUser()->getProfileData()->getContactName();
(...)
}

But PHPUnit rises an exception when calling the second function:

BadMethodCallException: Method demeter_getUser::getProfileData() does not exist on this mock object

If i just invert the two function calls, as well as shouldReceive() calls, PHPUnit claims that the non-existing function is the other one, getCustomers. It seems that only the first chain added is correctly mocked.
Am i missing something? Or is there an issue with multiple demeter chain mocking?
Thanks!

PHP Fatal error: Call to undefined method PHP_CodeCoverage_Filter::getInstance()

Hi,
I try to using PHPUnit Integration, but I have a problem...

PHP Fatal error: Call to undefined method PHP_CodeCoverage_Filter::getInstance() in /usr/share/php/Mockery/Adapter/Phpunit/TestListener.php on line 46
PHP Stack trace:
PHP 1. {main}() /usr/bin/phpunit:0
PHP 2. PHPUnit_TextUI_Command::main($exit = uninitialized) /usr/bin/phpunit:44
PHP 3. PHPUnit_TextUI_Command->run($argv = array (0 => '/usr/bin/phpunit'), $exit = TRUE) /usr/share/php/PHPUnit/TextUI/Command.php:125
PHP 4. PHPUnit_TextUI_TestRunner->doRun($suite = class PHPUnit_Framework_TestSuite { protected $backupGlobals = NULL; protected $backupStaticAttributes = NULL; protected $name = 'Unit test suite'; protected $groups = array ('nogroup' => array (...)); protected $tests = array (0 => class PHPUnit_Framework_TestSuite { ... }); protected $numTests = 1; protected $testCase = FALSE }, $arguments = array ('listGroups' => FALSE, 'loader' => NULL, 'useDefaultConfiguration' => TRUE, 'configuration' => '/home/imerayo/PhpstormProjects/point-of-sale/tests/phpunit.xml')) /usr/share/php/PHPUnit/TextUI/Command.php:187

I only add to my phpunit.xml

<listeners>
    <listener class="\Mockery\Adapter\Phpunit\TestListener"
              file="Mockery/Adapter/Phpunit/TestListener.php">
    </listener>
</listeners>

My enviroment is

php -v

PHP 5.3.6-13ubuntu3.3 with Suhosin-Patch (cli) (built: Dec 13 2011 18:18:37)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies
with Xdebug v2.1.2, Copyright (c) 2002-2011, by Derick Rethans
with Suhosin v0.9.32.1, Copyright (c) 2007-2010, by SektionEins GmbH

pear list -c phpunit

Installed packages, channel pear.phpunit.de:

Package Version State
DbUnit 1.1.1 stable
File_Iterator 1.3.0 stable
PHPUnit 3.6.5 stable
PHPUnit_MockObject 1.1.0 stable
PHPUnit_Selenium 1.1.3 stable
PHP_CodeCoverage 1.1.1 stable
PHP_Invoker 1.0.1 stable
PHP_Timer 1.0.2 stable
PHP_TokenStream 1.1.1 stable
Text_Template 1.1.1 beta
phpcpd 1.3.5 stable
phploc 1.6.4 stable
ppw 1.0.4 stable

pear list -c deepend

Installed packages, channel pear.survivethedeepend.com:

Package Version State
Mockery 0.7.1 stable

Sorry but my poor english.
Thanks!

Expectations don't throw exceptions anymore?

This simple code doesn't throw any exception anymore for me:

set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../vendor/mockery/mockery/library/');

require_once 'Mockery/Loader.php';
$loader = new \Mockery\Loader;
$loader->register();

$myMock = \Mockery::mock('MyMock');
$myMock->shouldReceive('MyMethod')->once();

I've installed Mockery using Composer.
The composer.json file says I'm using Mockery 0.7.2.
I'm using PHP 5.3.10 on Mac OS 10.7.4.

Partial mock of an object using __call()

When creating a partial mock of an object using __call() we get a BadMethodCallException if we use a method that should be catch by __call() :

<?php
class SoCool
{
    public function iDoSomethingReallyCoolHere()
    {
        return 3;
    }
}

class Gateway
{
    public function __call($method, $args)
    {
        $m = new SoCool();
        return call_user_func_array(array($m, $method), $args);
    }
}


$g = new Gateway();
echo $g->iDoSomethingReallyCoolHere() . "\n";

$mock = \Mockery::mock(new gateway());
echo $mock->iDoSomethingReallyCoolHere() . "\n";

The probleme come from the use of method_exists to check if the method exists in the partial mock.

Mockery\Container::mock is a "god method"

What exactly are the benefits of having one single method for all creation modes? I think having one method par creation mode is much more practical:

  • code become self-documented: you can see at a glance what the different options are and how to use them
  • makes it easier to add mock creation methods (I'm thinking about creating mock inheriting from not declared classes here, will post an issue on that too)
  • reduce the magic and complexity in the mock() method

What do you think?

Demeter chain mocking broken?

When I try to mock a demeter chain...

$mock = m::mock('shock');
$mock->shouldReceive('zebra->kobra')->andReturn('both dead');

I get Argument 1 passed to Mockery\CompositeExpectation::add() must be an instance of Mockery\Expectation, instance of Mockery\CompositeExcpectation given, called in Mockery.php on line 3.

More informative response when failing with() match

The following code:

        $publishOptions = array(
            'reply_to' => $requestId,
            'correlation_id' => $requestId . '-1',
            'headers' => array('a' => 'b')
        );
        $this->amqpExchange->shouldReceive('publish')
            ->once()->with(equalTo($body), equalTo($key),
                           nullValue(), $publishOptions);

Produced this test failure:

Mockery\Exception: No matching handler found for Fake_AMQPExchange::publish("<req></req>", "oxicaller", "", Array). Either the method was unexpected or its arguments matched no expected argument list for this method

It would be nice to be able to provide more information on the exact part of the match which failed, or a list of the matches which are available - perhaps even which one matched 3 out of 4 arguments!

I'm unsure whether this would make sense to be on by default, or as some sort of verbose mode.

If i find some time, I may try and work on this myself - but i'd happily accept guidance about the direction to take.

Strange behaviour when installing via Composer

Hi Padraic

When I install mockery/mockery (0.7.2) as a dependency via Packagist, I get a strange unpacking problem. This happens on Travis CI as well as on my local Windows machine while a few days ago the same action didn't cause any problems.

During

php composer.phar install

I get this

/path/vendor/mockery/mockery/309c934etcetc.2 is not a valid zip archive, got error cod 19.

Error code 19 means ZIPARCHIVE::ER_NOZIP.

Could this be caused by something you did to that tag or do I have to file an issue for composer?

Partial mock is not working with $this

Hi,

I am having problem with partial mock and use of $this inside of it.

I will put some code sample to be clearer.

In my test I have something like below:

$serviceMock = Mockery::mock('Service');
$serviceMock->shouldReceive('spam')->andReturn('eggs');

$foobar = Mockery::mock(new Foobar($foo));
$foobar->shouldReceive('getService')
    ->andReturn($serviceMock);

$foobar->useService();

In my real code I have something like this:

class Foobar {
    public function __construct($foo) { 
        $this->foo = $foo;
    }

    public function useService() {
        $bacon = $this->foo->bacon();

        $service = $this->getService();
        $eggs = $service->spam();

        return $bacon + $eggs;
    }

    public function getService() {
        return new RealService(); // hits network and I don't want to hit it
    }
}

I was migrating a PHPUnit test to Mockery and I had this problem, I believe one way to do it is using Injection, something like setService($service), but right now I have a huge code base that works with PHPUnit. Is this a bug of Mockery or something expected to happen?

Thanks for your help!

Create mock from not declared classes

To avoid loading un-needed code in my tests, I'd like to be able to create a mock that inherits a class that is not declared in the global scope yet. For example, Mockery could include the non-existent class's declaration in the eval'd code.

This would be particularly helpful to test code making heavy use of static classes (yes propel, I'm looking at you)

PHP 5.3.2 requirement

The readme says the only requirement is PHP 5.3, yet trying to install Mockery with 5.3 or 5.3.1 fails due to a dependency to PHP 5.3.2. Is there any reason for this particular dependency, or can it be set back to 5.3 safely?

How to mock an iterator?

I've got a class that implements the iterator interface. It implements, next, rewind, etc.

I've got the following code to try and mock it:

$user_object = Mockery::mock('user');
$db_iterator = Mockery::mock('db_iterator');
$db_iterator->shouldReceive('next')
    ->times(5)
    ->andReturn($user_object);

I want it to run 5 times. When I do foreach ($db_iterator as $row) it doesn't iterate at all.

What's the proper way to do this?

Your blog is down again

... just as I needed it to convince someone that DI as internal agent is wrong. :) Do you need a tip for a good hosting partner? Just kidding.

Allow property mocking

Some classes (probably poorly coded) have public variables, which are accessed from the outside, and mockery currently doesn't support this type of mocking. My workaround was just to asign a variable to the mock, but that's just shitty.

close() throws exception

When I call close I get an exception from $container->mockery_teardown()

#0 /usr/local/zend/share/pear/Mockery/Generator.php(90) : eval()'d code(194): __isset()
#1 /usr/local/zend/share/pear/Mockery/Container.php(197): mockery_verify()
#2 /usr/local/zend/share/pear/Mockery/Container.php(182): mockery_verify()
#3 /usr/local/zend/share/pear/Mockery.php(75): mockery_teardown()
#4 /Users/mark/NetBeansProjects/TrailheadVagabond-git/tests/library/Vag/Seo/MapTest.php(30): close()
#5 /usr/local/zend/share/pear/PHPUnit/Framework/TestCase.php(657): tearDown()
#6 /usr/local/zend/share/pear/PHPUnit/Framework/TestResult.php(666): runBare()
#7 /usr/local/zend/share/pear/PHPUnit/Framework/TestCase.php(576): run()
#8 /usr/local/zend/share/pear/PHPUnit/Framework/TestSuite.php(757): run()
#9 /usr/local/zend/share/pear/PHPUnit/Framework/TestSuite.php(733): runTest()
#10 /usr/local/zend/share/pear/PHPUnit/TextUI/TestRunner.php(305): run()
#11 /private/var/folders/CM/CMzmh-Qq2RWsCE+kNQqdc++++TI/-Tmp-/phpunit_TrailheadVagabond_git_mark.php(485): doRun()
#12 /private/var/folders/CM/CMzmh-Qq2RWsCE+kNQqdc++++TI/-Tmp-/phpunit_TrailheadVagabond_git_mark.php(774): runTest()
#13 /private/var/folders/CM/CMzmh-Qq2RWsCE+kNQqdc++++TI/-Tmp-/phpunit_TrailheadVagabond_git_mark.php(853): main()```

My entity object is throwing an exception when you try to access a property that doesn't exist and _mockery_ignoreVerification does not seem to exist.

Simple mock object not passing 'instanceof' test

When I use a phpUnit mock:

$mock = $this->getMock('Lib_Some_Class_Name');

the following:

($mock instanceof Lib_Some_Class_Name)

will be true. If I do the same with a Mockery mock

 $mock = m::mock('Lib_Some_Class_Name');

it doesn't. What am I doing/understanding wrong?

Strange behavior after update to 0.7.0

Hi, PΓ‘draic.

Today I've updated mockery to the latest from githib that is 0.7.0 and discivered some strange bahevior - all my tests are suddenly failing with some strange message when tearDown() is done.

Here's the message:

  1. MessageService_Cache_SaveTest::testCanClearThreadMessagesCacheByTag
    BadMethodCallException: Method RequestScope::__isset() does not exist on this mock object

And the call stack:

/library/Mockery/Container.php:197
/library/Mockery/Container.php:182
/library/Mockery.php:71
/library/Shift/Test/Case.php:172

The problem appears to be related to the mocked class having an __isset() method. But that was fine in previous Mockery versions...

I'm going to revert back to previous version for now.
Please tell me if I can give you any firther informstion on this issue.

Dmitry.

Use it's own namespace and namespaced functions

It would be great if instead of \Mockery::* there were namespaced function we could import and use without \Mockery 'prefix class', like this:

use \Mockery;
$mock = mock('stdClass')->shouldReceive('aMethod')->with(type('resource'))->andReturn('something')->mock();
doSomethingTo($mock);

Mocking abstract class protected methods

When you try to mock an abstract class protected methods, the result of those when used within the code is NULL. When it's used (via reflection) from outside you can get the result wich is set from the mock.

Mocking demeter chains fails with fatal error

I did try mocking demeter chains like described in the documentation. Example file:

register(); $mock = \Mockery::mock('CaptainsConsole'); $mock->shouldReceive('foo->bar->zebra->alpha->selfDestruct')->andReturn('Ten!'); This file results in a fatal error with Mockery version 0.6.3 and 0.7 from PEAR. Used PHP version: 5.3.3 Error message: PHP Catchable fatal error: Argument 1 passed to Mockery\CompositeExpectation::add() must be an instance of Mockery\Expectation, instance of Mockery\CompositeExpectation given, called in /home/jostick/PhpstormProjects/Ndx/vendor/pear/Mockery.php on line 300 and defined in /home/jostick/PhpstormProjects/Ndx/vendor/pear/Mockery/CompositeExpectation.php on line 39 PHP Stack trace: PHP 1. {main}() /home/jostick/PhpstormProjects/Ndx/vendor/pear/test.php:0 PHP 2. Mockery\Mock->shouldReceive() /home/jostick/PhpstormProjects/Ndx/vendor/pear/test.php:16 PHP 3. Mockery::parseShouldReturnArgs() /home/jostick/PhpstormProjects/Ndx/vendor /pear/Mockery/Mock.php:157 PHP 4. Mockery\CompositeExpectation->add() /home/jostick/PhpstormProjects/Ndx/vendor/pear/Mockery.php:300

Partial mocking methods that call methods on the same class

The following will always fail because of how proxy objects are implemented. Is there any way around this?

class Foo
{
    public function a()
    {
        echo "a";
        $this->b();
    }

    public function b()
    {
        echo "b";
    }
}

$mock = \Mockery::mock(new Foo());
$mock->shouldReceive("b")->once();
$mock->a();

\Mockery::close();

Uncaught exception 'Mockery\CountValidator\Exception' with message 'Method b() from Foo should be called
exactly 1 times but called 0 times.

Enhancement: Integrate Hamcrest for argument matching

The PHP port of Hamcrest (http://code.google.com/p/hamcrest/) supplies a fairly comprehensive set of matchers that can be applied to the arguments passed to a mocked method expectation.

$mock->shouldReceive(...)
     ->with(integerValue(), containsString('foo'), closeTo(3.14159, 0.001));

Adding support to \Mockery\Expectation::_matchArg() would look just like the code that checks for the Mockery matchers:

...
if ($expected instanceof \Hamcrest_Matcher) {
    return $expected->matches($actual);
}
return false;

Another possibility would be to wrap each Hamcrest_Matcher received by with() in a simple adapter, but that would require iterating over the arguments ahead of time to build the adapters.

Of course, the "obvious" choice would be to use Hamcrest as the matching library so you don't have to create a parallel set of matchers in Mockery. ;)

Partially Mocking and Pass by Reference Params

Partially mocking a class with a function that is passed a reference creates a strict function compatibility error.

class Test {
    function testFunction(&$a) { return true; }
}

\Mockery::mock(new Test());

'Declaration of Mockery_4ce2f0b118645::foo() should be compatible with that of Test::testFunction()'

Unit test forthcoming.

Problem mocking abstract class with __wakeup and __construct

I'm trying to mock Zend_Db_Adapter_Abstract, and get an exception thrown "BadMethodCallException: Method :: _ _wakeup() does not exist on this mock object". Looking at the method mock in Container.php, it calls _getInstance which unserializes the mocked object if it has a constructor. This appears to happen before the $quickdefs are applied, so I'm not sure how you can mock an abstract object that has _ _wakeup and __construct defined?

Thanks for the work on this - it's made my testing much easier!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.