What is the difference between createMock and getMockBuilder in phpUnit? - php

For the love of my life I can't figure out the difference between createMock($type) and getMockBuilder($type)
I am going through the original documentation and there is just a one liner which I didn't understand.
... you can use the getMockBuilder($type) method to customize the test double generation using
a fluent interface.
If you can provide me an example, I would be grateful. Thanks.

createMock($type) uses getMockBuilder() internally:
protected function createMock($originalClassName)
{
return $this->getMockBuilder($originalClassName)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->getMock();
}
So the createMock() method will return you a mock built with the general best-practice defaults.
But with getMockBuilder($type), you can create a mock with your own requirements.

From the manual
https://phpunit.de/manual/current/en/test-doubles.html
The createMock($type) and getMockBuilder($type) methods provided by
PHPUnit can be used in a test to automatically generate an object that
can act as a test double for the specified original type (interface or
class name). This test double object can be used in every context
where an object of the original type is expected or required.
The createMock($type) method immediately returns a test double object
for the specified type (interface or class). The creation of this test
double is performed using best practice defaults (the __construct()
and __clone() methods of the original class are not executed and the
arguments passed to a method of the test double will not be cloned.
If these defaults are not what you need then you can use the
getMockBuilder($type) method to customize the test double generation
using a fluent interface.
They are already plenty answers on stack overflow what are fluent interfaces.

Related

why is it impossible to test a static method with mockery or anything else

I have read in laravel's facade documentation the following sentence:
Typically, it would not be possible to mock or stub a truly static
class method.
1) question 1: I'm trying to understand facade in laravel. As I guess, it's implemented because if we have classes, and they have big namespaces and big names and every time we want to use this class and we don't want to use new keyword and use statements, we use the facade which is an easier code and readable. I also think that laravel implemented facades because they wanted to write non-static functions in their classes so that they could be tested. After all of this, we use facades like static classes (because of readability and not using new and use), but in reality, it makes new instances.
Am I right?
2) If the above is right, can you provide me an example why it's not possible to test a static method as laravel docs said?
A facade does not solve the big namespaces problem you mentioned. Big namespaces are solved using aliases. You can declare them in your config/app.php and internally Laravel will use class_alias when you call them. This is how e.g. \Cache or \DB work.
A facade is basically a proxy class to a singleton object instance of another class (the facade itself ensures the instance is a singleton).
Typically to register a singleton in Laravel you:
Add app()->singleton(ABC::class) in your service provider
Access it via app()->make(ABC::class)->...
A facade basically takes care of that for you if you haven't already registered that class as a singleton.
Basically a facade is a way to proxy that singleton instance of another class.
Also it's generally not possible to mock or stub static methods however if you are using facades you can do \ABCFacade::swap($mockObject) and therefore your facades can be mocked.
It is also false that you cannot test a static method. You can absolutely test a static method. For example:
public testStaticMethod() {
$this->assertEquals(1, ABC::method()); // We tested a static method against a desired behaviour
}
What you usually can't do is mock a static method. Here's how you would typically mock something with PHPUnit:
public testWithDependency() {
$dependency = $this->getMockBuilder(Dependency::class)->getMock();
$dependency->expects($this->once())->method('dependantMethod')->willReturn(true);
$objectToTest = new ABC($dependency); //We're passing a fake dependency which behaves in an ideal way
$this->assertEquals(1, $objectToTest->methodToTest()); //Any calls to the dependency will call mock methods and not real ones
}
The problem arises when trying to mock a static method. As you can see mocking creates mock instances of a certain type. It can't mock the static members of that type because the mock object itself is not actually of that type.
However as I just found out the statement that it's not possible to mock or stub a static method is not entirely true. There's the AspectMock you can mock static methods or helper methods. This seems to work by intercepting all function calls via a custom autoloader.
This being said, just because you can doesn't mean it's good practice to use static methods, there's other issues to consider like e.g. you normally can't have static interfaces in most programming languages or you normally can't override static methods in most programming languages. Note the "in most programming languages" part here. In PHP it's entirely possible to override static methods with late static binding but that means you need to make a conscious decision about this when implementing the static method.
Another disadvantage is that a class of statics can't implement an interface because interfaces apply to object behaviours and not the static behaviour. Therefore you can't swap out one interface for another if you are using statics which is a major disadvantage.
In general the aversion to static methods is not because of testability but because if you are coding in OOP you are really limited if you are using statics.
Hopefully this will help clear up some confusion.

Adding interface to mock with Mockery (hard dependency)

I need to mock CurrencyEnum by overload it, but it's not the end becouse i need to add interface to this mock.
This doesn't work:
Mockery::mock('overload:'.CurrencyEnum::class);
Error: (..) must be an instance of \BaseCurrency, instance of \CurrencyEnum given.
I looked at Mockery\Container::mock and I dont't have idea how to do it.
In example I want to test TestingClass::first() method
class CurrencyEnum implements BaseCurrency
{
/* methods */
}
class TestingClass
{
public function first(string $currencySymbol)
{
$abc = 'some_string';
return $this->second($abc, new CurrencyEnum($currencySymbol));
}
private function second(string $abc, BaseCurrency $currency)
{
/* code */
}
}
The overload method works by intercepting the autoload mechanism: it registers an autoloader for the overloaded class, loading the mocked version of the class instead of the original.
By default, it does not add many things to the mocked class. You can, however, configure just about anything you may need.
Usually, implementing one or more interfaces can be done by providing a comma-separated list of fully qualified names, the first one being the class:
$mock = Mockery::mock('MyClass, MyInterface, OtherInterface');
Due to the way that the Mockery::mock method is set up, this will not work. (The author apologises in the source code)
However, we can pass the interface(s) as second argument to the mock method:
Mockery::mock('overload:'.CurrencyEnum::class, BaseCurrency::class);
This will cause the MockConfigurationBuilder to add BaseCurrency as target; since it's an interface it will make the mock implement the interface.
An alternative notation of the above would be to use the builder directly:
Mockery::mock(
(new MockConfigurationBuilder())
->setInstanceMock(true)
->setName(CurrencyEnum::class)
->addTarget('stdClass')
->addTarget(BaseCurrency::class)
)
Having said that, it's a notoriously bad practice to mock things like enums and value objects. Why not just use the actual CurrencyEnum? Something as simple as a currency code does not quite warrant mocking at all. There's probably a structural improvement to make, which would simultaneously add tons of value to your tests and make them simpler to read.

What's the difference between App::singleton and bindShared?

The Laravel docs indicate that the appropriate way to bind a singleton is with the App::singleton() method, but internally Laravel will use the bindShared() method (for example, in TranslationServiceProvider).
I assume that the documented approach is preferred, but is there a functional difference? If not, is there any reason for having two approaches (beyond maybe historical accident)?
I've been wondering the same thing. I don't know the motivations behind this, but I can speak to a few differences.
Here is the definition of the two methods from Laravel 4.2:
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
public function bindShared($abstract, Closure $closure)
{
$this->bind($abstract, $this->share($closure), true);
}
Similarities:
Both methods call bind() under the hood.
Both methods pass true to the 3rd parameter of bind(), which signifies that this is a shared object.
In both cases, because this is a shared object, a call to isShared($abstract) will return true.
In both cases, because this is a shared object, a call to make($abstract) will return only the first instance.
Differences:
singleton() will accept a Closure or a string. bindShared() will only accept a Closure, not a string.
bindShared(), in addition to binding the object into the IOC container as a shared object, takes the additional step of wrapping the passed Closure in a share'd Closure, which prevents the passed Closure from being executed more than once. At first glance, this appears to be a double assurance that the object will be treated as a singleton. I can only guess why this might be desirable.
bindShared() is called 87 times inside the framework. singleton() is called 0 times.
They are (were) functionally identical, except that bindShared() only accepts closures.
Thus bindShared() has been deprecated in Laravel 5.1 (PR 9009 - commit 829060f) and removed in Laravel 5.2 (PR 9037).
Case finally solved :)
bind($abstract, $concrete, $shared)
Adds $abstract as a key to the container, with $concrete being the concrete class to instantiate in its place. Mainly used for providing a concrete implementation for an interface.
share($closure)
Given a closure (only), makes it act as if it was shared (instance/singleton style), and returns it. Technically equivalent to App::bind($key, $closure, true) but goes about it a different way. Mainly used in service providers to add a fully resolvable service to the IoC container.
bindShared($abstract, $closure)
A shortcut that was introduced in 4.1 that caters to a common pattern. Essentially helps those who want to bind a shared instance in the container. See below for example.
singleton($abstract, $concrete)
Simply an alias to bind with the $shared argument set to true. Mainly used for providing a concrete implementation for an interface, but one that should only have one instance (database connection, etc.)."
This is from http://alexrussell.me.uk/laravel-cheat-sheet/ I think this link should be helpfull
I think mainly for backwards compatibility. Singleton explains better behavior than bindShared. Removing bindShared would mean Package developers to refactor their code.

constructor methods in interfaces

Are constructor methods in interfaces bad?
Why do people think that anybody wants to instantiate the interface?
What we want to do is to force implementers to implement the constructor, just like other interface methods.
An interface is like a contract. Let's say I have an interface Queue, and I want to make sure that implementers create a constructor with one argument, which creates a singleton queue (A new queue with just that element). Why should that not be part of the contract? With at least Java interfaces, that cannot be specified.
They are bad in that they serve no purpose. At its core, an interface is simply a data passing contract. There is no implemenation attached with an interface and hence there is nothing to initialize and no need for a constructor.
If you need some sort of initialization your much better off using an abstract class.
First off, I disagree that interface is just a data passing contract. If that were true you would be allowed to define properties in an interface.
I wouldn't exactly think it's weird to do something like:
interface IDBConnection
{
function __construct( $connectionString );
function executeNonQuery( $commandText, $paramters=null);
function executeScalar( $commandText, $paramters=null);
function executeSingle( $commandText, $paramters=null);
function executeArray( $commandText, $paramters=null);
}
This would enable you to create instances of third party classes for data access based on simple reflection instead of just being a data contract.
I'm pretty sure that this isn't the best example, I'd go for an abstract base class here in the real world, but I'm also pretty sure that there are perfectly valid reasons for defining a constructor methods' contract in an interface that I haven't thought of.
I haven't seen it done, but i wouldn't think it to be weird or bad.
Although interfaces can't have constructors in most languages, the Factory pattern provides a contract for constructing objects, similar to an interface. Take a look at that.
Whether or not they are bad, I am not aware of any language that has the ability to specify a constructor on an interface.
That being said, however, I personally do not believe that the constructor of an object is part of that object's interface and as such adding a constructor to an interface would inhibit the natural flexibility that interfaces afford.
You have to instantiate immutable polymorphic objects sometime via their constructor that requires parameters and you may need that constructor in the interface for the exact same reasons you may need the other public methods in the interface, for example…
Say you have to instantiate a polymorphic object, its class implementing your interface and being supplied by the client code. As a dumb but simple scenario let's say this object is a value object and as such should be immutable, which mean the object's state should be valid from the moment it's instantiated…
$immutablePolymorphe = $userConfig['immutable_polymorphe_class'];
$immutablePolymorphe = new $immutablePolymorphe($state);
// Then do something with that polymorphe...
So what if you don't define the constructor with its parameter in the interface? Hence the reason why I believe a constructor in an interface can be as much legitimate as any other public method in an interface…
I don't know why Google sent me here :)
But the question is an interesting one, and I have seen some people in many projects defining the constructor in the interface. But I really think it is a useless restriction. No client of this class can call __construct.
And defining it in the interface does not restrict any behavior, still I can implement it as I wish, I can even have an empty function like:
...
function __construct(string $name) {}
...
Then what is the benefit from it? It just blocks you from doing polymorphism, without any single benefit.
So if you have:
<?php
interface Shape {
function __construct(int $width, int $height);
public function getArea();
}
class Square implements Shape {
public function __construct(int $width, int $height) {...}
public function getArea(){...}
}
// This will throw an exception because it does not implement the correct constructor signature!
class Circle implements Shape {
public function __construct($radius) {...}
public function getArea(){...}
}
And even if you want to extend Square, then you have to implement the same constructor!.
And there is an example in the answers like:
You have to instantiate immutable polymorphic objects...
and example looks like:
$immutablePolymorphe = $userConfig['immutable_polymorphe_class'];
$immutablePolymorphe = new $immutablePolymorphe($state);
// Then do something with that polymorphe...
That is smart thinking, but only if you can restrict the strings in the $userConfig array to be of a specific interface! Which is not possible at least to my knowledge.
So bottom line :D I think having __construct in the interface is bad and blocks you from evolving your software, and it encourages you to have bad workarounds.

Mock Objects in PHPUnit to emulate Static Method Calls?

I am trying to test a class that manages data access in the database (you know, CRUD, essentially). The DB library we're using happens to have an API wherein you first get the table object by a static call:
function getFoo($id) {
$MyTableRepresentation = DB_DataObject::factory("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
...you get the idea.
We're trying to test this method, but mocking the DataObject stuff so that (a) we don't need an actual db connection for the test, and (b) we don't even need to include the DB_DataObject lib for the test.
However, in PHPUnit I can't seem to get $this->getMock() to appropriately set up a static call. I have...
$DB_DataObject = $this->getMock('DB_DataObject', array('factory'));
...but the test still says unknown method "factory". I know it's creating the object, because before it said it couldn't find DB_DataObject. Now it can. But, no method?
What I really want to do is to have two mock objects, one for the table object returned as well. So, not only do I need to specify that factory is a static call, but also that it returns some specified other mock object that I've already set up.
I should mention as a caveat that I did this in SimpleTest a while ago (can't find the code) and it worked fine.
What gives?
[UPDATE]
I am starting to grasp that it has something to do with expects()
I agree with both of you that it would be better not to use a static call. However, I guess I forgot to mention that DB_DataObject is a third party library, and the static call is their best practice for their code usage, not ours. There are other ways to use their objects that involve constructing the returned object directly. It just leaves those darned include/require statements in whatever class file is using that DB_DO class. That sucks because the tests will break (or just not be isolated) if you're meanwhile trying to mock a class of the same name in your test--at least I think.
When you cannot alter the library, alter your access of it. Refactor all calls to DB_DataObject::factory() to an instance method in your code:
function getFoo($id) {
$MyTableRepresentation = $this->getTable("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
function getTable($table) {
return DB_DataObject::factory($table);
}
Now you can use a partial mock of the class you're testing and have getTable() return a mock table object.
function testMyTable() {
$dao = $this->getMock('MyTableDao', array('getMock'));
$table = $this->getMock('DB_DataObject', ...);
$dao->expects($this->any())
->method('getTable')
->with('mytable')
->will($this->returnValue($table));
$table->expects...
...test...
}
This is a good example of a dependency in your code - the design has made it impossible to inject in a Mock rather than the real class.
My first suggestion would be to try and refactor the code to use an instance rather than a static call.
What's missing (or not?) from your DB_DataObject class is a setter to pass a prepared db object before calling the factory method. That way you can pass a mock or a custom db object (with the same interface) should the need arise.
In your test setup:
public function setUp() {
$mockDb = new MockDb();
DB_DataObject::setAdapter($mockDb);
}
The factory() method should return the mocked DB instance. If it's not already integrated into your class, you will probably have to refactor the factory() method as well to make it work.
Are you require/including the class file for DB_DataObject in your test case? If the class doesn't exist before PHPUnit tries to mock the object you can get errors like this.
With PHPUnit MockFunction extension plus runkit you can also mock static methods. Be careful, because it's monkey patching and therefore should only be used in extreme cases. Does not substitute good programming practices.
https://github.com/tcz/phpunit-mockfunction

Categories