PHPUnit "Mocked method does not exist." when using $mock->expects($this->at(...))

phpunit tutorial
phpunit example
phpunit windows
phpunit documentation
phpunit versions
phpunit --filter
phpunit setup
phpunit laravel

I've run into a strange issue with PHPUnit mock objects. I have a method that should be called twice, so I'm using the "at" matcher. This works for the first time the method is called, but for some reason, the second time it's called, I get "Mocked method does not exist.". I've used the "at" matcher before and have never run into this.

My code looks something like:

class MyTest extends PHPUnit_Framework_TestCase
{
    ...

    public function testThis()
    {
        $mock = $this->getMock('MyClass', array('exists', 'another_method', '...'));
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));
    }

    ...
}

When I run the test, I get:

Expectation failed for method name is equal to <string:exists> when invoked at sequence index 1.
Mocked method does not exist.

If I remove the second matcher, I do not get the error.

Has anyone run into this before?

Thanks!

The issue ended up being with how I understood the "at" matcher to work. Also, my example was not verbatim how it is in my unit test. I thought the "at" matcher counter worked on a per query basis, where it really works on a per object instance basis.

Example:

class MyClass {

    public function exists($foo) {
        return false;
    }

    public function find($foo) {
        return $foo;
    }
}

Incorrect:

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(0))
             ->method('find')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue('foo'));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertEquals('foo', $mock->find('foo'));
        $this->assertFalse($mock->exists("bar"));
    }

}

Correct:

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('find')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue('foo'));

        $mock->expects($this->at(2))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertEquals('foo', $mock->find('foo'));
        $this->assertFalse($mock->exists("bar"));
    }

}

Quickly Perform PHP Unit Testing With PHPUnit, Edition for PHPUnit 9.1. Updated on Apr 04, 2020. Sebastian Bergmann. This work is licensed under the Creative Commons Attribution 3.0 Unported License. PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks.

FYI, Not sure if its related, but I encountered the same thing, but not with the $this->at() method, for me it was the $this->never() method.

This raised the error

$mock->expects($this->never())
    ->method('exists')
    ->with('arg');

This fixed the error

$mock->expects($this->never())
    ->method('exists');  

It did the same thing when using the $this->exactly(0) method.

Hope this help someone.

Tutorial: Introduction to Unit Testing in PHP with PHPUnit, PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit architecture for unit testing frameworks that originated with  composer require --dev phpunit/phpunit ^9 ./vendor/bin/phpunit --version PHPUnit 9.0.0 by Sebastian Bergmann and contributors. Please refer to the documentation for details on how to verify PHAR releases of PHPUnit .

Try changing $this->at(1) to $this->at(2)

Unit Testing Tutorial: What is, Types, Tools, EXAMPLE, PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks. Latest Stable Version  PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit architecture for unit testing frameworks that originated with SUnit and became popular with JUnit. PHPUnit was created by Sebastian Bergmann and its development is hosted on GitHub. 1 Purpose

This is an unfortunate wording of the error message by PHPUnit.

Double check the order of your calls, like @rr's answer mentions.

For me, as far as I know with my own code, I should be using at(0) and at(1) respectively, but it wasn't until I used at(2) and at(3) instead that it worked. (I'm using session mocking in CakePHP.)

The best way to check the order is to get 'into' the called method and check what's passed. You can do that like this:

$cakePost = $this->getMock('CakePost');
$cakePost->expects($this->once())
->method('post')
->with(
    // Add a line like this for each arg passed
    $this->callback(function($arg) {
        debug("Here's what was passed: $arg");
    })
);

PHPUnit is a framework independent library for unit testing PHP. Unit testing is a method by which small units of code are tested against  PHPUnit for VSCode. This extension aims to need zero config and to be highly configurable. If you have php in environment path and phpunit installed with composer or anywhere in your workspace as phpunit*.phar, zero config is needed.

As far as i can tell from the Demo code it should work. I produced a working example in case you are running an older PHPUnit Version and want to check that way if it works for you too.

In case that doesn't help maybe you could provide a bit more (at best executable) code ? :)

<?php

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertFalse($mock->exists("bar"));
    }

}

class MyClass {

    public function exists($foo) {
        return false;
    }
}

printing

phpunit MyTest.php
PHPUnit 3.4.15 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 4.25Mb

OK (1 test, 3 assertions)

I will use `PHPUnit` as the main test tool for PHP Unit Testing. Once you get hold of the basics, getting started with PHPUnit is not that difficult. Even a small  PHPUnit. PhpStorm supports unit testing of PHP applications through integration with the PHPUnit testing framework.. Before you start. Make sure the PHP interpreter is configured in PhpStorm on the PHP page, as described in Configure local PHP interpreters and Configure remote PHP interpreters.

With PHPUnit, the most basic thing you'll write is a test case. A test case is just a term for a class with several different tests all related to the same  The word `Unit` refers to a block of code, method or an individual or independent class. Unit testing is a software testing process in which code blocks are checked to see whether the produced result matches the expectations.  The units are tested by writing a unique test case.

Unit testing with PHPUnit: Writing your first test (3/10). Codecourse. Loading Unsubscribe from Duration: 4:19 Posted: Jan 24, 2017 PHPUnit Manual. Edition for PHPUnit 9.1. Updated on Apr 04, 2020. Sebastian Bergmann. This work is licensed under the Creative Commons Attribution 3.0 Unported License.

during the development (coding phase) of an application by the developers. phpunit-testlistener-xhprof Archived A TestListener for PHPUnit that uses XHProf for automated profiling of the tested code. PHP 20 39 1 0 Updated May 15, 2015

Comments
  • Yes, but I think it is a bug in PHPUnit. The documentation says: Returns a matcher that matches when the method it is evaluated for is invoked at the given $index.
  • Agree, plus it would be much easier and more useful to spy method calls if the at() index would be incremented on a per-method basis.
  • Looks like just about any mistaken usage of expects will cause the "Mocked method does not exist" message. Good to know.
  • That makes mocking more than one method virtually unusable
  • today it still works like that, and now that I fixed my test with this post, I slam my hat onto the floor
  • Thanks! This was really helpful, I ran into the same problem and I was stuck (until I read your comment).
  • Thanks, that fixed my problem too. But I really have no idea why it worked. Can you shed some light on the matter?
  • @SilviuG, since the method is never supposed to be called, the expectation about the with arguments should never happen. So since the configured expectation for the method did not happen but was configured to happen (because of the with), the error is trigger. Hope it makes sense. I agree that the message is kind of weird for this error.
  • Thank you! Had exact same problem.
  • Worked for me. I've called: once for foo and 3 times for bar methods after foo. Starting bar expectation from 1 fixed problem.
  • Holy hell, that's annoying! Thanks for this, I was really struggling with a unit test due to exactly this problem.
  • Yep, the first matcher works fine, which is the head scratcher