I'm trying to test a method of a class in my laravel project with mockery.
However, when I attempt to test the phpunit says a my interface class (which is being used in the method I need to test) is not instantiable.
What's wrong?
My test class
class HelperRSTest extends TestCase {
public function tearDown()
{
Mockery::close();
}
public function test_mockery()
{
// $mock = Mockery::mock('HelperRS');
// $mock->shouldReceive('getRecibosLocacao')->once()->andReturn('mocked');
$result = HelperRS::getRecibosLocacao(1228);
var_dump($result);
}
}
My target class to test
class HelperRS extends \BaseController {
public static function getRecibosLocacao($id_locacao){
$pagamentos = App::make('PagamentoRepositoryInterface');
$locacao = Locacao::find($id_locacao);
$pagamento = $pagamentos->getByVendaByTipo($locacao->cod_locacao, 'l');
dd($pagamento);
}
}
The error:
1) HelperRSTest::test_mockery
Illuminate\Container\BindingResolutionException: Target [PagamentoRepositoryInterface] is not instantiable.
The method you are calling on HelperRS is a static method, whereas you are creating a mocked instance of that class and not actually doing anything with it. You can achieve this with mockery, though it is not recommended and will require you to run the test in process isolation.
$mock = Mockery::mock('alias:HelperRS');
$mock->shouldReceive('getRecibosLocacao')->once()->andReturn('mocked');
Related
I have a Basic Class Helper.
namespace App\Helpers;
class CommonUtility {
public static function foo() {
return 'foo';
}
}
And it's used in User.php
<?php
class User extends Authenticatable
public function test() {
return CommonUtility::foo();
}
}
And now I wanted to write a test with mocking CommonUtility class. Can anyone know about this I'm new to laravel unit test.
Tried few solutions like
$mock = Mockery::mock(CommonUtility::class, function ($mock) {
$mock->shouldReceive('foo')->andReturn('foobar');
})->makePartial();
dd($mock->foo());
it gives me the mock result but i tried it from
$user = new \App\User();
dd($user->test());
It's calling the actual function instead of mock one.
You could use the Aliasing Mockery features for Mocking Public Static Methods
As example:
$mock = \Mockery::mock('alias:App\Helpers\CommonUtility');
$mock->shouldReceive('foo')
->andReturn('foobar');
$user = new User();
$this->assertEquals("foobar", $user->test());
The test pass as expected
I'm having difficulty with the spy and mock in Laravel 7 test when I test for MyCustomClass.
I have tried both mock before running $this->get and spy after $this->get. Both with the same error message (*below).
When running debug in the controller the $myCustomClass is still the MyCustomClass and not the mocked object.
MyCustomClass
class MyCustomClass
{
public function execute()
{
return 'hello';
}
MyController
class MyController
{
public function show()
{
$myCustomClass = new MyCustomClass();
$data = $myCustomClass->execute();
return $data;
}
private $mySpy;
public function testAMethod()
{
$spy = $this->spy(MyCustomClass::class);
$response = $this->get('/my/path');
$spy->shouldHaveReceived('execute');
$response->assertStatus(200);
}
Error
Method execute(<Any Arguments>) from Mockery_2_App_MyCustomClass should be called
at least 1 times but called 0 times.
The problem is that you are instantiating MyCustomClass yourself with the new keyword.
In order for Laravel to be able to swap out the real class with the spy you have to use the service container.
Something like this:
class MyController
{
public function show(MyCustomClass $myCustomClass)
{
return $myCustomClass->execute();
}
}
I have the following class
namespace MyApp;
use MyApp\SomeInterface;
class MyClass
{
public function __construct(SomeInterface $s)
{
//Some Logic here
}
//Another methods implemented There
}
The SomeInterface contains the following:
namespace MyApp
interface SomeInterface
{
/**
* #return SomeObject
*/
public function someMethodToImpement();
}
And I want to create a mock over my phpunit Test Class:
namespace Tests\MyApp;
use PHPUnit\Framework\TestCase;
use MyApp\MyClass;
use MyApp\SomeInterface;
class MyClassTest extends TestCase
{
public function someTest()
{
$fakeClass=new class{
public function myFunction($arg1,$arg2)
{
//Dummy logic to test if called
return $arg1+$arg2;
}
};
$mockInterface=$this->createMock(SomeInterface::class)
->method('someMethodToImpement')
->will($this->returnValue($fakeClass));
$myActualObject=new MyClass($mockInterface);
}
}
But Once I run it I get the error:
Tests\MyApp\MyClassTest::someTest
TypeError: Argument 1 passed to MyApp\MyClass::__construct() must implement interface MyApp\SomeInterface, instance of PHPUnit\Framework\MockObject\Builder\InvocationMocker given, called in /home/vagrant/code/tests/MyApp/MyClassTest.php on line
Do you know why that happens and how actually will create the mock Interface?
Instead of constructing the mock via
$mockInterface=$this->createMock(SomeInterface::class)
->method('someMethodToImpement')->will($this->returnValue($fakeClass));
Split it into seperate lines:
$mockInterface=$this->createMock(SomeInterface::class);
$mockInterface->method('someMethodToImpement')->will($this->returnValue($fakeClass));
And will work like a charm.
I've had a similar issue. I fixed it by adding those interfaces as another mock() parameter
class Product implements PriceInterface, ProductDataInterface {
// ...
}
Test:
// throws error
$product = Mockery::mock(Product::class);
// works fine
$product = Mockery::mock(Product::class, 'PriceInterface, ProductDataInterface');
Link to documentation
I can't get Mockery to create a simple dummy:
<?php
require_once '../vendor/autoload.php'; // composer autoload mockery
class Foo {
private $required;
public function __construct($required){
$this->required = $required;
}
public function bar(){
// do stuff with $this->required
}
}
class FooTest extends PHPUnit_Framework_TestCase {
public function testBar(){
$mock = \Mockery::mock('\Foo');
$mock->bar();
}
}
Running that PHPUnit test gives the error:
BadMethodCallException: Method Mockery_0_Foo::bar() does not exist on this mock object
What am I doing wrong?
If you'd like to do php unit testing on "Foo" class and mocks "Required" object. Just do it like below:
class Foo {
private $required;
public function __construct(\Required $required){
$this->required = $required;
}
public function bar(){
return $this->required->getTextFromBarTable();
}
}
class FooTest extends PHPUnit_Framework_TestCase {
public function testBar(){
$mock = \Mockery::mock('\Required'); // Dummy, There are no properties or methods.
/**
* Stub "getTextFromBarTable" method of \Required class
* and fakes response by returning "return this text".
*/
$mock->shouldReceive('getTextFromBarTable')
->andReturn('return this text');
// create "Foo" Object by using $mock instead of actual "\Required" Object.
$foo = new Foo($mock);
$response = $foo->bar();
$this->assertEqual('return this text', $response);
}
}
You must NOT stub or mock class that you want to do unit testing on. Just do it on Dependency Class like "\Required".
we do STUB or MOCK to separate EXTERNAL logic that could affect INTERNAL logic of method we're going to test. In this case I assumed \Required class has "getTextFromBarTable" method and this method will connect and get 'text' field from database. The "testBar" method will be broken if our database doesn't have text field. To get rid of external problems I did stub on "\Required" and every times I use "getTextFromBarTable" method. It will always return me "return this text".
I had to explicitly state what methods the mock makes stubs of:
class FooTest extends PHPUnit_Framework_TestCase {
public function testBar(){
$mock = \Mockery::mock('Foo');
$mock->shouldReceive('bar');
$mock->bar();
}
}
I'm curious if there's a way round this, something which either:
implicitly catches all method calls that are defined in Foo, or
implicitly catches all method calls, whether or not they are defined in Foo
I am using PHPUnit to unit test my application (using Zend Framework 2). I am stuck in a situation where I need to call a method that is in one test class
from another test class. Let me explain myself with a small example:
<?php
// TestUser.php
namespace Test\User;
class UserTest extends \PHPUnit_Framework_TestCase
{
public static function GetUserCount(){
// some code here
}
}
?>
<?php
// TestAdmin.php
namespace Test\Admin;
use Test\User;
class AdminTest extends \PHPUnit_Framework_TestCase
{
public static function AdminAction(){
Test\User::GetUserCount();
}
}
?>
When I call the Test\User::GetUserCount(); or User::GetUserCount(); I get the following error:
PHP Fatal error: Class 'Test\User' not found in path/to/TestAdmin.php
on line 11
Any idea if the method is callable from one test class to another test class? If yes, how?
Thanks
Normally, you would Mock the other class call, to ensure the returned values are what your class is expecting. You may also link some test together with Test Dependencies.
I have added a short sample. Note, I assume you added the AdminAction and GetUserCount() as samples since these are not really test methods that you would have with PHPUnit tests.
TestUser.php
<?php
namespace Test\User;
class UserTest extends \PHPUnit_Framework_TestCase
{
protected $UserObject;
public function setUp()
{
$this->UserObject = new Test\User(); // Normal Object
}
public static function testGetUserCount()
{
$this->assertEquals(1, $this->UserObject->GetUserCount(), 'Testing the basic object will return 1 if initialized'); // Do your tests here.
}
}
TestAdmin.php
<?php
namespace Test\Admin;
class AdminTest extends \PHPUnit_Framework_TestCase
{
protected $AdminObject;
public function setUp()
{
$this->AdminObject = new Test\Admin();
}
public static function testAdminAction()
{
// Create a stub for the User class.
$stub = $this->getMock('User');
// Configure the stub.
$stub->expects($this->any())
->method('GetUserCount')
->will($this->returnValue(2));
// Calling $stub->GetUserCount() will now return 2. You can then ensure the Admin class works correctly, by changing what the mocks return.
$this->assertEquals(2, $stub->GetUserCount());
}
}