I am getting Error: Call to undefined method Mock_SimpleInterface_8a93e777::mymethod() when I call the mymethod() on the Simple class mock.
class PlaygroundTest extends \PHPUnit_Framework_TestCase
{
public function testMock()
{
$class = $this->getMockBuilder('\Playground\Simple')->getMock();
$class->mymethod();
}
}
The Simple class implementation
namespace Playground;
class Simple
{
public function mymethod()
{
print "Hey!";
}
}
According to PHPUnit docs (https://phpunit.de/manual/5.1/en/test-doubles.html), it states that "By default, all methods of the original class are replaced with a dummy implementation that just returns null (without calling the original method)."
Shouldn't I be able to call mymethod() and get a null return value? I want to avoid to specify all class methods. PHPUnit should be clever enough to know which methods can be called on the mock or not.
Is this a bug? I'm using PHPUnit 5.1.4
Your assumptions are correct, so you have an error somewhere else or did not show the real code.
The mock class name Mock_SimpleInterface_8a93e777 suggests that you don't actually mock \Playground\Simple but rather \Playground\SimpleInterface, which probably does not contain mymethod()
Related
I am having trouble setting up Mockery to work in my application. I need to make a partial mockery of a library class that has a few functions in it that need to be mocked while other functions are tested. It seems like its failing to pick up the basic ShouldRecieve() function from mockery and instead trying to dig through MyClass for an instance of it. I've created an example of what is going on below.
<?php
class MyClass {
function foo() { return $this->bar; } // to be tested
function bar() { return true; } // to be mocked
}
class MyClass_Test extends TestCase {
function testMyClassFoo() {
$mock = \Mockery::mock('MyClass')->makePartial();
$mock->shouldRecieve('bar')->once()->andReturn(true);
$result = $mock->foo();
$this->assertTrue($result);
}
}
When I try to run the tests I'll get the following error:
Mockery\Exception\BadMethodCallException: Method Mockery_0_MyClass::shouldRecieve() does not exist on this mock object
I am thinking there must be something wrong with the Mockery installation but it all seems to be there. Any ideas why this might happen?
I know you've provided an example but I'm assuming your error is the real thing.
The method is shouldReceive().
So I am making a Magento module in PHP. I want my logging to be consistent across all classes. My idea was to define a method in the helper class and call it. However being the pre-optimizer that I am, I figure making multiple calls to a class via the Mage::Helper() method to be more expensive than it needs to be, especially since most of my logging in singleton models anyways. So my now my idea is to use closures, define my method in the helper, make one call to the helper and register the method in a class variable.
class Comp_Mod_Helper_Data extends Mage_Core_Helper_Abstract {
public function getLogger() {
return function ($obj, $type= Zend_Log::DEBUG) {
Mage::log($obj, $logType, 'comp-mod.log', true);
};
}
}
Use:
class Comp_Mod__IndexController extends age_Core_Controller_Front_Action {
private $_log;
protected function _construct() {
$this->_log = Mage::Helper('mod')->getLogger();
}
}
However while it works ... it is not great to use. I'm either stuck doing:
$log = $this->_log;
$log('hello world');
// one awkward liner
($this->_log)('hello world');
While neat that it works is not readable nor standard, i.e. confusing!. The error that it get when using $this->_log('hello world'); is that the method does not exist. I assume because PHP is looking for a method call when using the syntax $this->method();
I do understand that A) I could just suck it up and use Mage::Helper everywhere, and B) that I could store the helper object in a variable and call like $this->helper->log(), and C) that static variables work, see PHP closure as static class variable
So, is there a way to get a non-static class variable to call the closure instead of looking for a non-existing method?
You could make use of the __call magic method:
class Comp_Mod__IndexController extends age_Core_Controller_Front_Action {
public function __call($method, array $args)
{
switch ($method)
{
case '_log':
return call_user_func_array(Mage::Helper('mod')->getLogger(), $args);
}
return null;
}
}
Then use it like you wanted to:
$this->_log('string to log');
Is there a way to make PHPUnit throw an exception if a method being stubbed does not originally exist in the class being stubbed?
Here's a crude example:
class User {
function getId() { ... }
}
class LoginTest extends PHPUnit_Framework_TestCase {
function testLogin() {
...
$userMock = $this->getMockBuilder('User')
->setMethods(['getID']) // getId is misspelled; error should occur
->getMock();
...
}
}
class Login {
function login($user) {
...
$id = $user->getID(); // tests will pass even though this is misspelled
...
}
}
#Schleis is right that you cannot do it in PHPUnit directly.
But as of PHPUnit 4.5 you can use Prophecy to create test doubles. Prophecy will not tolerate this behavior. You won't be able to mock a non-existing method with it.
No, you can't.
PHPUnit doesn't need to have the class available to mock it. And you can even set the mock to not use any autoloading. When this happens, PHPUnit creates a fake class on the fly. This fake class doesn't have any defined methods which would cause an exception to be thrown, failing your tests suite.
Your tests should fail because of issues with the code that is being tested. Issues with the mock are outside of the scope of your test. The issue in your example would be caught during your functional testing.
There really isn't an easy way to tell between an misspelled function and one that hasn't been implemented yet.
I have run into a problem when mocking Interfaces using Mockery in PHP (im using the laravel framework but I'm not sure this is relevant.
I have defined an interface
<?php namespace MyNamespace\SomeSubFolder;
interface MyInterface {
public function method1();
}
And I have a class that typehints that interface on one of the methods...
<?php namespace MyNamespace\SomeSubFolder;
use MyNamespace\SomeSubFolder\MyInterface;
class MyClass {
public function execute(MyInterface $interface)
{
//does some stuff here
}
}
...and I am trying to test MyClass. I have created a test that looks something like this:
public function testExecute()
{
$mock = Mockery::mock('MyNamespace\SomeSubFolder\MyInterface');
$mock->shouldReceive('method1')
->andReturn('foo');
$myClass = new MyClass();
$myClass->execute($mock);
}
When I run the test I receive the message
'ErrorException: Argument 1 passed to MyClass::execute must be an instance of MyNamespace\SomeSubFolder\MyInterface, instance of Mockery_123465456 given....'
I have no idea why.
Within the test I have tried the following :
$this->assertTrue(interface_exists('MyNamespace\SomeSubFolder\MyInterface'));
$this->assertTrue($mock instanceof MyInterface);
and both return true, so it appears as if I have created and instance that implements the interface, but when I call the method on the class it disagrees. Any ideas???
You should call mock() method at the and of mock declaration.
$mock = Mockery::mock('MyNamespace\SomeSubFolder\MyInterface');
$mock->shouldReceive('method1')
->andReturn('foo')
->mock();
I think the problem is with PHP class loading. Your 'MyNamespace\SomeSubFolder\MyInterface' class isn't available from your test file.
You'll need to modify your composer.json to autoload that namespace or you'll need a require_once('path/to/file/containing/namespace/MyInterface.php') at the top of your test.
Although, when you did try the interface_exists it seemed to pass. It could also be that you misspelled your namespaced class when you mocked it. I've made that mistake as well.
In any case, Mockery isn't able to see that the class exists so it's just inventing one.
Can you provide your full test source?
The code to be tested
abstract class Parent
{
public function getSomething(){} //this has to be mocked
}
class Child extends Parent
{
public function methodWhichIsTested()
{
$something = $this->getSomething(); //call to parent method
}
}
The test
public function setUp()
{
$this->child = new Child;
}
public function testTheChildMethod()
{
$this->child->methodWhichIsTested();
}
How can I add mock expectations to the instantiated class Child?
I would like to do something like:
MockFramework->takeExistingClass('Child')->shouldRecieve('getSomething')->andReturn('whatever');
My problem is, that in the real case (not the example), the getSomething method returns a dependency, which I need to mock!
I am using Mockery but if you know how to do this with phpUnit mocks, go ahead! Maybe I'm making a basic thinking mistake, please give me a hand! Thanks.
After you clarfied in chat that the returned value of getSomething holds a dependency that is
a protected property of the abstract class, and it is injected into that abstract via another public method of the abstract
the solution is inject a mock of that dependency via that other method.
In general, you should never have the need to mock or stub behavior of the TestSubject. It is only when you are making lookups to the Global Scope or mix/hard code object creation into the TestSubject, that you might see the need for that, but these would be code smells and should be refactored instead. See Sebastian Bergmann's articles on untestable code:
Testing private methods
Testing code that uses singletons
Stubbing static methods
Stubbing hard-coded dependencies