Testing overriden trait method execution - php

I have situation like this. I have some 3rd party trait (I don't want to test) and I have my trait that uses this trait and in some case runs 3rd party trait method (in below example I always run it).
When I have code like this:
use Mockery;
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase
{
/** #test */
public function it_runs_parent_method_alternative()
{
$class = Mockery::mock(B::class)->makePartial();
$class->shouldReceive('fooX')->once();
$this->assertSame('bar', $class->foo());
}
protected function tearDown()
{
Mockery::close();
}
}
trait X {
function foo() {
$this->something->complex3rdpartyStuff();
}
}
trait Y2 {
function foo() {
$this->fooX();
return 'bar';
}
}
class B {
use Y2, X {
Y2::foo insteadof X;
X::foo as fooX;
}
}
it will work fine however I don't want code to be organized like this. In above code in class I use both traits but in code I want to test in fact trait uses other trait as mentioned at the beginning.
However when I have code like this:
<?php
use Mockery;
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase
{
/** #test */
public function it_runs_parent_method()
{
$class = Mockery::mock(A::class)->makePartial();
$class->shouldReceive('fooX')->once();
$this->assertSame('bar', $class->foo());
}
protected function tearDown()
{
Mockery::close();
}
}
trait X {
function foo() {
$this->something->complex3rdpartyStuff();
}
}
trait Y {
use X {
foo as fooX;
}
function foo() {
$this->fooX();
return 'bar';
}
}
class A {
use Y;
}
I'm getting:
undefined property $something
so it seems Mockery is not mocking in this case X::foo method any more. Is there are way to make possible to write such tests with code organized like this?

So far it is not possible to mock deeper aliased methods. You can proxy aliased method call using local method and allowing mocking protected methods.
Check code below
use Mockery;
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase
{
/** #test */
public function it_runs_parent_method()
{
$mock = Mockery::mock(A::class)->shouldAllowMockingProtectedMethods()->makePartial();
$mock->shouldReceive('proxyTraitCall')->once();
$this->assertSame('bar', $mock->foo());
}
protected function tearDown()
{
Mockery::close();
}
}
trait X {
function foo() {
$this->something->complex3rdpartyStuff();
}
}
trait Y {
use X {
foo as fooX;
}
function foo() {
$this->proxyTraitCall();
return 'bar';
}
function proxyTraitCall() {
return $this->fooX();
}
}
If you autoload trait you can try to overload it using Mockery.
/** #test */
public function it_runs_parent_method()
{
$trait = Mockery::mock("overload:" . X::class);
$trait->shouldReceive('foo')->once();
$class = Mockery::mock(A::class)->makePartial();
$this->assertSame('bar', $class->foo());
}
Don't test implementation details. Test it like you use it.
Class user have to know only public interface to use it, why test should be any different?
Fact that one internal method call different one is implementation detail and testing this breaks encapsulation. If someday you will switch from trait to class method without changing class behaviour you will have to modify tests even though class from the outside looks the same.
From Pragmatic Unit Testing by Dave Thomas and Andy Hunt
Most of the time, you should be able to test a class by exercising its
public methods. If there is significant functionality that is hidden
behind private or protected access, that might be a warning sign that
there's another class in there struggling to get out.

Related

creating mock phpunit discrepency in mocked namespace and the original one

I have function like this:
class Bar{
public function a():Foo{
.
.
.
}
}
now I am trying to create a mock for the class Bar with php unit test
$mockedBar = $this->getMockBuilder(Bar::class)
->getMock()
->method('a')
->willReturn(new FakeFoo());
but when I am calling method a I am getting an error that method a return type must be instance of Foo not Mocked_blahblah.
unfortunately class Bar don't use any interface and the system is very big and I can't create an interface cause it make huge refactor in my codes;
is there any way to disable return type of function a in mocked object?
I am useing php7.2 and phpunit 6.0.13.
Here is a real scenario:
class A
{
public function b():B
{
echo "i am from class A function b";
}
}
class B
{
}
class FakeB
{
}
class ATest extends TestCase
{
public function testSayHi(){
$mockedA = $this->getMockBuilder(A::class)
->getMock();
$mockedA->method('b')->willReturn(new FakeB());
$mockedA->b();
}
}
You can't disable return types. Perhaps you could try to do it with some kind of a hackish error handler, but it's a crazy thing to do.
Good news is that you're not trying to do anything unusual and your tests can be fixed.
Firstly, you need to assign the result of getMock to a variable. Next, you can define your test double:
class MyTest extends TestCase
{
public function testIt()
{
$mockedBar = $this->getMockBuilder(Bar::class)->getMock();
$mockedBar
->method('a')
->willReturn(new FakeFoo());
$this->assertInstanceOf(Foo::class, $mockedBar->a());
}
}
This will only work if FakeFoo is of type of Foo, for example extends it:
class FakeFoo extends Foo
{
// override any Foo methods you'd like to fake
}
You don't need to create a Fake yourself, you can use PHPUnit to create a dummy:
class MyTest extends TestCase
{
public function testIt()
{
$mockedBar = $this->createMock(Bar::class);
$mockedBar
->method('a')
->willReturn($this->createMock(Foo::class));
$this->assertInstanceOf(Foo::class, $mockedBar->a());
}
}
To fix your second example:
class A
{
public function b():B
{
echo "i am from class A function b";
}
}
class B
{
}
class FakeB extends B
{
}
class ATest extends TestCase
{
public function testSayHi(){
$mockedA = $this->getMockBuilder(A::class)->getMock();
$mockedA->method('b')->willReturn(new FakeB());
$mockedA->b();
}
}
Or, instead of using a fake let phpunit handle it:
class ATest extends TestCase
{
public function testSayHi(){
$mockedA = $this->getMockBuilder(A::class)->getMock();
$dummyB = $this->createMock(B::class);
$mockedA->method('b')->willReturn($dummyB);
$mockedA->b();
}
}

PHP Traits: How to circumvenient constructors or force them to be called?

Have a look at the following trait:
trait PrimaryModelRest {
use RestController;
protected $primaryModel;
public function __construct() {
$mc = $this->getPrimaryModelClass();
try {
$this->primaryModel = new $mc();
if(!($this->primaryModel instanceof Model)) {
throw new ClassNotFoundException("Primary Model fatal exception: The given Class is not an instance of Illuminate\Database\Eloquent\Model");
}
} catch (Exception $e) {
throw new WrongImplementationException("Primary Model Exception: Class not found.");
}
}
/**
* #return string: Classname of the primary model.
*/
public abstract function getPrimaryModelClass();
// various functions here
}
As you can see the trait makes sure that the using class holds a certain model instance and it implements certain methods. This works as long as the implementing class does not override the constructor.
So here is my question: I want to make sure that either the constructor is called or a better solution, such that I can instantiate this model on initialization.
Please make in answer which respects Multiple inheritance as well es Multi-Level inheritance.
I think you are trying to make the trait do a job it is not designed for.
Traits are not a form of multiple inheritance, but rather "horizontal reuse" - they're often described as "compiler-assisted copy-and-paste". As such, the job of a trait is to provide some code, so that you don't have to copy it into the class manually. The only relationship it has is with the class where the use statement occurs, where the code is "pasted". To aid in this role, it can make some basic requirements of that target class, but after that, the trait takes no part in inheritance.
In your example, you are concerned that a sub-class might try to access $primaryModel without running the constructor code which initialises it, and you are trying to use the trait to enforce that; but this is not actually the trait's responsibility.
The following definitions of class Sub are completely equivalent:
trait Test {
public function foo() {
echo 'Hello, World!';
}
}
class ParentWithTrait {
use Test;
}
class Sub inherits ParentWithTrait {
}
vs:
class ParentWithMethodDefinition {
public function foo() {
echo 'Hello, World!';
}
}
class Sub inherits ParentWithMethodDefinition {
}
In either case, class Sub could have its own definition of foo(), and by-pass the logic you'd written in the parent class.
The only contract that can prevent that is the final keyword, which in your case would mean marking your constructor as final. You can then provide an extension point that can be overridden for sub-classes to add their own initialisation:
class Base {
final public function __construct() {
important_things(); // Always run this!
$this->onConstruct(); // Extension point
}
protected function onConstruct() {
// empty default definition
}
}
class Sub {
protected function onConstruct() {
stuff_for_sub(); // Runs after mandatory important_things()
}
}
A trait can also mark its constructor as final, but this is part of the code being pasted, not a requirement on the class using the trait. You could actually use a trait with a constructor, but then write a new constructor as well, and it would mask the trait's version completely:
trait Test {
final public function __construct() {
echo "Trait Constructor";
}
}
class Noisy {
use Test;
}
class Silent {
use Test;
public function __construct() {
// Nothing
}
}
As far as the trait is concerned, this is like buying a bottle of beer and pouring it down the sink: you asked for its code and didn't use it, but that's your problem.
Crucially, though, you can also alias the methods of the trait, creating a new method with the same code but a different name and/or a different visibility. This means you can mix in code from traits which declare constructors, and use that code in a more complex constructor, or somewhere else in the class altogether.
The target class might also use the "final + hook" pattern:
trait TestOne {
final public function __construct() {
echo "Trait TestOne Constructor\n";
}
}
trait TestTwo {
final public function __construct() {
echo "Trait TestTwo Constructor\n";
}
}
class Mixed {
final public function __construct() {
echo "Beginning\n";
$this->testOneConstructor();
echo "Middle\n";
$this->testTwoConstructor();
echo "After Traits\n";
$this->onConstruct();
echo "After Sub-Class Hook\n";
}
use TestOne { __construct as private testOneConstructor; }
use TestTwo { __construct as private testTwoConstructor; }
protected function onConstruct() {
echo "Default hook\n";
}
}
class ChildOfMixed extends Mixed {
protected function onConstruct() {
echo "Child hook\n";
}
}
The trait hasn't forced the Mixed class to implement this pattern, but it has enabled it, in keeping with its purpose of facilitating code reuse.
Interestingly, the below code doesn't work, because the as keyword adds an alias, rather than renaming the normal method, so this ends up trying to override the final constructor from Mixed:
class ChildOfMixed extends Mixed {
use TestTwo { __construct as private testTwoConstructor; }
protected function onConstruct() {
$this->testTwoConstructor();
echo "Child hook\n";
}
}
Use a base class, this will let you handle the trait as a parent.
<?php
trait StorageTrait
{
public function __construct()
{
echo "Storage Trait";
}
}
class StorageAttempt
{
use StorageTrait;
public function __construct()
{
parent::__construct();
echo " - Storage Attempt";
}
}
abstract class StorageBase
{
use StorageTrait;
}
class MyStorage extends StorageBase
{
public function __construct()
{
parent::__construct();
echo ' - My Storage';
}
}
new StorageAttempt(); // won't work - will trigger error
new MyStorage(); // will display "Storage Trait - My Storage"
Also if you are using traits you can also work with properties and getters & setters.
Example: A Storage trait involves that a Storage Engine will be used. You can add the storageEngine property and its getters and setters. (with or without Type Hinting)
interface StorageEngineInterface{}
trait StorageTrait
{
/**
* #var StorageEngineInterface
*/
protected $storageEngine;
/**
* #return StorageEngineInterface
*/
public function getStorageEngine(): StorageEngineInterface
{
return $this->storageEngine;
}
/**
* #param StorageEngineInterface $storageEngine
*/
public function setStorageEngine(StorageEngineInterface $storageEngine)
{
$this->storageEngine = $storageEngine;
return $this;
}
}
Note: this is just an explanation so you can better understand how Traits work
UPDATE
To avoid conflict you can use aliases for trait methods. This way you can use both constructors (from trait and from extended class) you can do the following
class DifferentStorage
{
public function __construct()
{
echo ' diff ';
}
}
class MyDifferentStorage extends DifferentStorage
{
use StorageTrait {
StorageTrait::__construct as otherConstructor;
}
public function __construct()
{
parent::__construct();
self::otherConstructor();
}
}
You could use the interface injection pattern: implement an interface iPrimaryModelRest into the same class that uses the trait PrimaryModelRest:
interface iPrimaryModelRest {
public function init();
public abstract function getPrimaryModelClass();
}
The class that uses the trait woud look like this:
class cMyClass implements iPrimaryModelRest {
use PrimaryModelRest;
}
Then, whenever the class is instantiated (not only autoloaded) you could call a special factory-like initialisation function like this:
class cMyApp {
public function start() {
/** #var cMyClass $oClass */ // enlighten IDE
$oClass = $this->init(new cMyClass);
}
public function init($oClass) {
if ($oClass instanceof iPrimaryModelRest) {$oClass->init();}
if ($oClass instanceof whateverinterface) {
// pass optional stuff, like database connection
}
}
}
The interface is used to determine the capabilities of the class, and sets data/runs corresponding functions. If I'm not mistaken then this pattern is called a Service Locator.
I needed a trait for database connection. To avoid using the __construct in a trait, I've used a magic getter instead:
trait WithDatabaseConnection
{
public function __get(string $name)
{
if ($name === 'pdo') {
return App::make(\PDO::class);
}
trigger_error("Property $name does not exist.");
return null;
}
}
class Foo {
use WithDatabaseConnection;
public function save() {
$this->pdo->query('...');
}
}

PHP Unit: Create common object to work with

I'm writing PHP Unit tests for a class, which make some curl requests. At the moment every test starts with my class instance initiation and login directive and ends with logout directive, e.g.
public function testSomeMethod(){
$a = new myClass();
$a->login();
....
$a->logout();
$this->assertTrue($smth);
I want to create one common object $a = new myClass(), call login method before all test and logout method after all tests. How can I do that?
In accordion with the PHPUnit documentation here you can use the following hook method:
The setUp() and tearDown() template methods are run once for each test
method (and on fresh instances) of the test case class.
Also
In addition, the setUpBeforeClass() and tearDownAfterClass() template
methods are called before the first test of the test case class is run
and after the last test of the test case class is run, respectively.
In your case you can define the login class as class member and instantiate (login) in the setUpBeforeClass() method and do the logout in the tearDownAfterClass()
EDIT: EXAMPLE
Consider the following class:
namespace Acme\DemoBundle\Service;
class MyService {
public function login()
{
echo 'login called'.PHP_EOL;
}
public function logout()
{
echo 'logout called'.PHP_EOL;
}
public function doService($name)
{
echo $name.PHP_EOL;
return $name;
}
}
This test case:
use Acme\DemoBundle\Service\MyService;
class MyServiceTest extends \PHPUnit_Framework_TestCase {
/**
* #var \Acme\DemoBundle\Service\MyService
*/
protected static $client;
public static function setUpBeforeClass()
{
self::$client = new MyService();
self::$client->login();
}
public function testSomeMethod1()
{
$value = self::$client->doService("test1");
$this->assertEquals("test1",$value);
}
public function testSomeMethod2()
{
$value = self::$client->doService("test2");
$this->assertEquals("test2",$value);
}
public static function tearDownAfterClass()
{
self::$client->logout();
}
}
Dump the following output:
login called .test1 .test2 logout called
Time: 49 ms, Memory: 6.00Mb
OK (2 tests, 2 assertions)
hope this help
Creating reusable / common object at class level ( to be use in methods/functions) answer by #Matteo was helpful, Here is my implementation
no need for multiple inheritance , or __construct() constructor, I spent a lot of time on that ( specially coming from java background)
<?php
namespace Tests\Unit;
use Tests\TestCase;
use App\Services\HelperService;
class HelperServiceTest extends TestCase
{
//Object that will be reused in function()'s of this HelperServiceTest class itself
protected static $HelperServiceObj;
//this is the magic function
public static function setUpBeforeClass()
{
self::$HelperServiceObj = new HelperService();
}
public function testOneHelperServiceToBeTrue()
{
$this->assertTrue(self::$HelperServiceObj->getValue());
}
public function testTwoHelperServiceToBeTrue()
{
$this->assertTrue(self::$HelperServiceObj->getValueTwo());
}
}
Refer official docs setUp() , setUpBeforeClass() , tearDown() for magic function like setUpBeforeClass()
Sample implementation of getValue() function in HelperServiceTest class
<?php
namespace App\Services;
class HelperServiceTest
{
function getValue(){
return true;
}
function getValueTwo(){
return true;
}
}

Show warning when overriding method

I have some abstract class MyClass with foo method. It is important to call this method from child class when someone iherits from this class and override this methods. So I want to show warning when this situation will happen. But I can't modify child class, because it isn't designed by me. In addition foo method can be overriden but not have to.
In code, calling FirstClass::foo() should cause warning, but SecondClass::foo() not. How can I do this?
abstract class MyClass {
public function foo() {
// do something important
}
}
class FirstClass extends MyClass {
public function foo() {
// do something special
}
}
class SecondClass extends MyClass {
public function foo() {
parent::foo ();
// do something special
}
}
You cannot do this right. You could add to your abstract class some flag and check it, but it would be wrong.
I propose you to use Template method pattern instead.
abstract class MyClass {
final public function foo() {
// do something important
$this->_overridableMethod();
}
abstract protected function _overridableMethod();
}
class FirstClass extends MyClass {
protected function _overridableMethod(){
// do something special
}
}
Here is skeleton example of how I would do this:
interface VehicleInterface
{
public function move($x, $y);
public function refuel($station);
}
interface FlyableInterface
{
public function takeoff();
public function land();
}
abstract class AbstractVehicle implements VehicleInterface
{
/**
* Implementation to refuel at station
*/
public function refuel($station)
{
}
}
class Car extends AbstractVehicle
{
/**
* Implementation to move by following a road.
*/
public function move($x, $y)
{
}
}
class Plane extends AbstractVehicle implements FlyableInterface
{
/**
* Implementation to move by means of flying.
*/
public function move($x, $y)
{
}
/**
* Override of AbstractVehicle::refuel, landing required first.
*/
public function refuel($station)
{
$this->land();
parent::refuel($station);
}
/**
* Implementation for plane to take off.
*/
public function takeoff()
{
}
/**
* Implementation to land the plane.
*/
public function land()
{
}
}
$vehicles = array(new Car(), new Plane());
$x = '145';
$y = '751';
foreach($vehicles as $vehicle) {
if($vehicle instanceof FlyableInterface) {
$vehicle->takeoff();
$vehicle->move($x, $y);
$vehicle->land();
} else {
$vehicle->move($x, $y);
}
}
The executing script at the end intends to perform the same task for each vehicle differently depending on the methods each class implements. Both the plane and the car implement the same move method, and they both inherit the the same refuel method, however the plane is required to land first.
The executing script will detect what methods are supported by checking if it is an instance of a particular interface.
For an example in practice, Symfony2 class Command has a variant called ContainerAwareCommand. By extending this, the framework knows to inject the service container because the supported methods to do so are either inherited or implemented by the child class.

PHPUnit Stubbing Class methods declared as "final"

I'm writing a unit test for a class method that calls another class's method using a mock, only the method that needs to be called is declared as final, so PHPUnit is unable to mock it. Is there a different approach I can take?
example:
class to be mocked
class Class_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
my test case
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$mock = $this->getMock('Class_To_Mock', array('needsToBeCalled'));
$mock->expects($this->once())
->method('needsToBeCalled')
->with($this->equalTo(array('option'));
}
}
Edit: If using the solution provided by Mike B and you have a setter/getter for the object you're mocking that does type checking (to ensure the correct object was passed into the setter), you'll need to mock the getter on the class you're testing and have it return the other mock.
example:
class to be mocked
class Class_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
mock
class Class_To_MockMock
{
public function needsToBeCalled($options)
{
...
}
}
class to be tested
class Class_To_Be_Tested
{
public function setClassToMock(Class_To_Mock $classToMock)
{
...
}
public function getClassToMock()
{
...
}
public function doSomething()
{
$this->getClassToMock()
->needsToBeCalled(array('option'));
}
}
my test case
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$classToTest = $this->getMock('Class_To_Be_Tested', array('getClassToMock'));
$mock = $this->getMock('Class_To_MockMock', array('needsToBeCalled'));
$classToTest->expects($this->any())
->method('getClassToMock')
->will($this->returnValue($mock));
$mock->expects($this->once())
->method('needsToBeCalled')
->with($this->equalTo(array('option'));
$classToTest->doSomething();
}
}
I don't think PHPUnit supports stubbing/mocking of final methods. You may have to create your own stub for this situation and do some extension trickery:
class myTestClassMock {
public function needsToBeCalled() {
$foo = new Class_To_Mock();
$result = $foo->needsToBeCalled();
return array('option');
}
}
Found this in the PHPUnit Manual under Chapter 11. Test Doubles
Limitations
Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.
I just stumbled upon this issue today. Another alternative is to mock the interface that the class implements, given that it implements an interface and you use the interface as type hinting.
For example, given the problem in question, you can create an interface and use it as follows:
interface Interface_To_Mock
{
function needsToBeCalled($options);
}
class Class_To_Mock implements Interface_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
class Class_To_Be_Tested
{
public function setClassToMock(Interface_To_Mock $classToMock)
{
...
}
...
}
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$mock = $this->getMock('Interface_To_Mock', array('needsToBeCalled'));
...
}
}

Categories