how to mock an exception thrown by a class' __construct - php

Imagine a class A istantiating a class B.
I'm trying to write a test for class A and mock the behavior of B.
B could throw some exception when istantiated, and that's what I want to mock with phpunit so as to test A properly.
Is it possible to mock the magic function __construct in some way?

Not with PHPUnit's mocking capability. You would need to redefine the class in your test so that B's __construct throws an exception. Except that this could cause errors to be thrown later when you are trying to test B or you want B to actually be constructed due to the class already being defined. These difficulties are a code smell that your code is not optimally designed.
Rather what you should be doing is passing B into A's __construct method. This is Dependency Injection. So you would create a mock of B and pass it in to A. This is clearer because if B's __construct throws an exception, this is a problem with B and not A. In general, you should avoid using new within your objects and instead pass them in (except in the case of Factory classes).

My opinion you have badly design your classes and a test case of a class must be always related to the class itself: you should not test a class B in a test for class A.
PHPUnit is not able to implement a test of this type but you could use another library (Mockery), that helps you to test this kind of dependencies. With Mockery you can do something like:
$mock = \Mockery::mock('MyClass');
$mock->shouldReceive('name_of_method_1')
->once()
->with($arg1)
->andReturn('return value');

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.

Mock an Exception in phpUnit

The method I am trying to test has a try catch like
try {
$fooClass->doStuff(); // Throws \Lib\Custom\Exception
}
catch (\Lib\Custom\Exception $exception) {
return false;
}
I want to test if the return is false, but the custom exception is not loaded when my tests are executed.
Php unit has the option of mocking classes, but I can't seem to use this for Exceptions.
$exceptionMock= $this->getMockBuilder(\Lib\Custom\Exception::class)->getMock();
$fooClassMock = $this->getMockBuilder(fooClass::class)->getMock()
->method('doStuff')
->willThrowException($exceptionMock);
Gives me the folowing exception:
Argument 1 passed to
PHPUnit_Framework_MockObject_Builder_InvocationMocker::willThrowException()
must be an instance of Exception, instance of Mock_Exception_c4dd9394 given
How to properly mock this Exception to test the function?
I don't think you need to mock the exception.
why not try this?
$fooClassMock = $this->getMockBuilder(fooClass::class)->getMock()
->method('doStuff')
->willThrowException(new \Lib\Custom\Exception());
Or something similar..
The reason that your test isn't working is because the class isn't known in the test. When that happens and you create a mock in PHPUnit, it does some trickery to create a class definition and then extends that to create the mock. Otherwise it would use the extend the class itself and you would not have had a problem.
In this case, PHPUnit creates a fake \Lib\Custom\Exception and then uses that to create the mock. The fake class created doesn't extend anything (since it wouldn't know what to extend/implement). So the type hint in the willThrowException will not be matched because your mock object didn't extend Exception.
This would happen with any type hinting for extended classes in PHPUnit if the class is not loaded in the test. In order to fix this, you need to have the class available in the test via a require, include, or autoloader.

Mocking the SUT itself

My question is about unit testing. Assume we have the class below;
class X
{
public function p1(){
//logic
$a = $this->p2();
//more logic
}
public function p2(){
//even more logic
}
}
When writing a unit test for p1 method, should I mock p2 method?
What I am thinking is that, the test that is written for p1 method should only execute and test the p1 method not p2. But in order to realize that I should get a mock of Class X and call p1 method on that mock instance like below.
$xMock = $this->getMockBuilder('\X')
->setMethods(array('p2'))
->getMock();
$xMock->expects($this->any())
->method('p2')
->will($this->returnValue($value));
$resultTobeAsserted = $xMock->p1();
Unfortunately doing that feels a little wrongish to me. I discussed the topic with my colleagues and it boiled down to how you define your SUT(system under test).
If a tester considers the particular method that is being tested as the SUT, then other methods that are called from the SUT would seem as dependencies and naturally tester will want to mock them. On the other hand if tester considers the whole class as the SUT, then those method calls will become part of the test so there won't be any reason to mock them.
Is that conclusion correct? Which kind of thinking would yield more robust unit tests?
When writing a unit test for p1 method, should I mock p2 method?
No.
You are calling a method on a class and you expects that things happen.
With mocking p2 you make exceptions on the implementation details on the class.
Unfortunately doing that feels a little wrongish to me.
I say the felling it spot on.
Which kind of thinking would yield more robust unit tests?
If you test the observable behaviors of a class you make sure that class still does what it was supposed to do when you change the implementation of the class. Thats robustness.
if you test one method and mock out part of the implementation of that method (the internal method call) then you test a specif implementation and if the test fails you don't know if the external behavior changed.
I've written about this in some more detail in:
The UNIT in unit testing.
which details a couple more points about why i think it's important to test behaviors and not methods.
In short
Unit testing, in PHP, is about testing the observable behaviors of a class!
Behaviors:
return values
calling other methods
modifying global state (writing to files, the db, $GLOBALS)
Test those things. Disregard implementation details.
If a tester considers the particular method that is being tested as the SUT, then other methods that are called from the SUT would seem as dependencies and naturally tester will want to mock them.
If there are arguments that support this separation, the same arguments can be used to refactor the class into two classes and this is exactly what you should to then.
Your thinking is correct. If you want test method p1 you don't care about p2 because you assume that it's been tested in another test. So, you can just mock/stub p2. But you have to remember that you should mock/stub ONLY p2. So you example should look more like:
$xMock = $this->getMockBuilder('\X')
->setMethods(array('p2'))
->getMock();
$xMock->expects($this->any())
->method('p2')
->will($this->returnValue($value));
$resultTobeAsserted = $xMock->p1();

PHPUnit - Writing a test class for an interface, and testing objects using a factory

I am writing a class that will inherit an interface. The client code will be written for that interface, and the class written to support it. The idea is that I will later write other classes for that interface, and objects of those two different classes should be completely interchangeable. Rather than writing a test class for that first class, I want to write one for the interface.
My plan was to write a test class that would take a factory object for the constructor (dependency injection), and use the factory to create new instances of the class under test.
That way, if I wanted to test ClassA, I could pass a ClassAFactory object to the constructor of the test class, and if I wanted to test ClassB, I would pass a ClassBFactory object. Both classes are designed to be interchangeable, and since only public methods are supposed to be tested, this seems ideal.
But what about testing the constructor? Would I be better writing an abstract test class and implmenting constructor tests in classes that inherit the abstract test class (different classes may be instantiated differently)?
If I did use the first idea, I guess I would have a test class for each class being tested, like:
class ClassATest extends [PHPUnit test case]
{
$myFactory = new ClassAFactory();
$myTest = new ClassTest($myFactory);
$myTest->test1();
$myTest->test2();
//etc.
}
What's the best way to go about this? I want to have a general test, so that when I write new classes to implement the common interface, I can just put an object of the same tests as used for the others. But, seeing as the different classes would have different constructors, perhaps writing an abstract test class and extending it for each new object would be better? What do you think?
I think you need to reconsider your plan. You can't test an interface and there's a good reason why - interfaces just define the API and not functionality, tests test functionality. Let me give you an example that might help. Say you have a "messaging" interface. So you implement an EmailMessager and an SMSMessager. Now you need to test these separately as with the EmailMessager you need to make sure it is doing its stuff, maybe validating the recipient (an email address) and possibly delegating the sending to an email class etc. Obviously an SMS message would be different.
You can create an abstract test case with all of the test methods using a property that each subclass will set without requiring a factory. It can test the fixed qualities that all implementations must posess.
abstract class IAdderTestCase extends PFTC
{
function testAdd() {
self::assertEquals(5, $this->fixture->add(2, 3));
}
...
}
class BasicAdderTest extends IAdderTestCase
{
function setUp() {
$this->fixture = new BasicAdder();
}
}
PHPUnit will call setUp() before each test method. It should call all inherited test methods for each concrete subclass plus any additional ones, e.g. to test the constructors.

What's the correct way to stub functionality for PHPUnit testing?

I'm trying to write some unit tests for a class that connects to an API.
What I want to do is alter the class so that instead of actually connecting to the API, it instead loads a pre-fetched constant fixture. The method within the class that actually does the cURL request and returns the data is protected, and this is the one I want to change to instead return the contents of the fixture file.
My question is what's the best way to do this?
I've read about mock objects in PHPUnit, but because the method I want to change is internal and protected, I don't think I can use those right?
Am I correct in assuming I will need to extend the class and alter the method myself?
Thanks.
The purpose of Mocks and Stubs is to replace relying on functionality of dependencies, e.g. when you have something like
class Foo
{
public function __construct($apiConnector) {
$this->apiConnector = $apiConnector
}
}
where $apiConnector is the dependency used to make the call to the API, then you stub or mock that dependency with your own implementation. Since that dependency is invoked through it's public facing interface by Foo, you stub the method that triggers the protected method within the dependency.
If, however, there is no dependency, but the call to the API is made from the testclass, then you have to write a custom class that extends your testclass and implements it's own API calling function, e.g.
class FooMock extends Foo
{
protected function queryAPI()
{
return $fixture;
}
}
You will then test this class instead of the actual class.
If your class is actually connecting to a WebService, see the chapter Stubbing and Mocking WebServices

Categories