I've just started using PHPUnit. Before this, I've used RSpec and Cucumber and their isolated environment where really nice.
I've done my first phpunit test and created 2 mock class, wondering if they will remain in my next test and, as I presumed, they will.
Now, I'm thinking of using a really specific namespace for all this helpers, something like this:
<?php
namespace Subject;
class FirstDependency { /* ... */ }
class TestableSubject extends \Subject { /* ... */ }
class SubjectTest extends \PHPUnit_Framework_TestCase {
/* tests */
}
Is there any better solution to avoid namespace cluttering?
I take the opportunity for another question: which is faster between a method call and a dynamic class instantiation ($s = 'MyClass'; $c = new $s;)?
Actually when I've a dependencies I just put it on a method, such us new_something() and then test a child class TestableSubject with that method overridden.
Again, any better way to do this?
Related
I am trying to use overload option of Mockery library on Laravel 5.
My current environment:
Laravel 5
Mockery 1.0
PHPUnit 7.5
I wrote this test case:
namespace Tests\Unit;
use Mockery;
use Tests\TestCase;
/**
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
*/
class RenewSignatureTest extends TestCase
{
public function testHandle()
{
$mock = Mockery::mock('overload:App\FooClass');
$mock->shouldReceive('callBar')
->times(2);
}
}
According to documentation, this test should fail, but does not matter what I do, the test never fails! It always result in:
Time: 304 ms, Memory: 19.53 MB
OK (1 test, 1 assertion)
If I remove the overload: option, the test fails. So I assume that I'm not using the library's methods as expected.
The new test:
namespace Tests\Unit;
use Mockery;
use Tests\TestCase;
/**
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
*/
class RenewSignatureTest extends TestCase
{
public function testHandle()
{
$mock = Mockery::mock('App\FooClass');
$mock->shouldReceive('callBar')
->times(2);
}
}
The result:
Mockery\Exception\InvalidCountException: Method callBar(<Any Arguments>) from Mockery_0__App_FooClass should be called exactly 2 times but called 0 times.
Am I doing anything wrong? Does anyone know how to use this option properly?
Reading the page, I think this is the error you are looking for:
When Mockery overloads a class, because of how PHP works with files,
that overloaded class file must not be included otherwise Mockery will
throw a “class already exists” exception. This is where autoloading
kicks in and makes our job a lot easier.
The error that you're looking for will be caused if you remove these 2 lines from your test, which are added to the code in the second code sample, and in the third sample on the manual page:
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
This means your code wont take advantage of the psr4 autoloader or any autoloader that is in place, and will create a new autoloader for you, at the expense of speed, since it wont be using your dumped classmap and has to build it up from scratch.
If you take the two lines above out, you will get the expected error, as it will try to overload your class with a class of the same name. That class will already be autoloaded, so you get a fatal error.
So if you want to block calls to callBar, and return void, that is what your code will be doing, which is correct.
Removing overload will mean your mock is no longer effective, as you will have to pass it through a constructor to get it to work.
Update:
With your update, I can conclude that your code must be running the mocked callBar method twice (not the actual callBar method), with your mock of fooBar class using overload. When the mocked method gets called, nothing inside the real callBar method actually happens, it just registers that it was called. If you're expecting it once for example, write shouldReceive(1) and then fix the code that your test runs.
When you remove the overload, the global injection doesnt take place, so your mock never gets injected. However, your mock callBar method on the mock class is still expecting to be ran twice, so you get the error. You will need to remove the 2 mock code lines completely from your test.
Keep the # statements in, as it will help prevent the psr4 error outlined above.
This is not the way to test, you should never use overload: option... Laravel helps you with a lot of things, don't create the wheel again or try to...
Why would you need to use #runTestsInSeparateProcesses and #preserveGlobalState disabled ?
Let's say your test is like this:
namespace Tests\Unit;
use App\FooClass;
use App\Service\ServiceForTesting;
use Mockery;
use Tests\TestCase;
class RenewSignatureTest extends TestCase
{
public function testHandle()
{
$mock = Mockery::mock(FooClass::class);
$mock->shouldReceive('callBar')
->times(2);
$myClass = app(ServiceForTesting::class);
$myClass->run($mock);
$myClass->run($mock);
}
}
You should have a code like this:
namespace App;
class FooClass
{
public function callBar()
{
return 'Works !!!';
}
}
Now, let's say you have a standalone class (no controller or similar, you are in a unit test), you should have something like this:
namespace App\Service;
use App\FooClass;
class ServiceForTesting
{
public function run(FooClass $class)
{
return $class->callBar();
}
}
I am currently on PHPUnit v5.7.27
I would like to create a mock object that uses an array of traits. How would I go about this? I only see getMockForTrait as a way to create a mock object using a single trait. My issue is that the trait requires the existence of another trait at the class level.
Update: More context to the issue
Given:
trait GetSet {
public function __call(){ /* does some magic */
}
trait RepositoryAware {
public function getRepository(string $name)
{
/* makes use of the GetSetTrait*/
}
}
class Controller
{
use GetSet;
use RepositoryAware;
}
Given the limitations of PHP, I can not simply put a use GetSet on the RepositoryAware trait because other traits that the controller imports could also bring the GetSet trait. Furhtermore, the controller class itself could be using the behavior provided by the GetSet trait.
The current solution I have is to create a Dummy Class that imports both traits and mock that class instead:
class RepositoryAwareClass
{
use GetSet;
use RepositoryAware;
}
Like this I am able to properly test the behavior provided by the RepositoryAware trait while at the same time composing its requirement of the GetSet trait.
Mocking concept was built with the idea that you would be using dependency injection. I can certainly see why you may not want to use dependency injection with this multiple inheritance like model that php uses called "Traits". Mocking tools like the one built for phpunit was built to substitute instances of objects not classes/interfaces/traits themselves. PHP Traits are more like having a static dependency instead of a dependency on an instance of an object. However, even if you were using traits and assuming a trait was basically the same as a class, according to mocking best practices should test the trait as its own test instead of testing a trait through another class. If you want to mock the trait itself you may want to try to revisit your design as I do not believe it can be done. You can certainly mock a trait and test that trait but you cannot mock a trait and then inject it as a dependency on an object. Imagine that a class for example implements an interface, mocking a trait would be the same a mocking an interface that a class implements, its not possible. You can only mock an interface of an object that a class depends upon through setter or constructor based dependency injection. Another example would be to try and mock the class that the class under test inherits from. You can't do that either. Perhaps in the javascript world this type of thing could be useful and from some people's point of view desired, but I think if you want to use mocking you would need to stick with object dependency injection instead of static use of traits.
So what's the alternative? I think the following example would be how to use perhaps "traditional" OOP practices with mocking to achieve your goal of sharing functionality without using inheritance. The example also makes your dependencies more explicit. And for the record, I applaud you for NOT using inheritance.
<?php
interface GetterSetter {
public function __call();
}
interface RepositoryProvider {
public function getRepository(string $name);
}
class GetSet implements GetterSetter {
public function __call() {
/* does some magic */
}
}
class DefaultRepository implements RepositoryProvider, GetterSetter {
/**
* #var GetterSetter
*/
private $_getterSetter;
public function __construct(GetterSetter $getterSetter) {
$this->_getterSetter = $getterSetter;
}
public function getRepository(string $name) {
// makes use of the GetSetTrait
$this->__call();
}
public function __call() {
// makes use of the GetSetTrait
$this->_getterSetter->__call();
}
}
class Controller implements RepositoryProvider, GetterSetter {
/**
* #var RepositoryProvider
*/
private $repositoryProvider;
public function __construct() {
$this->repositoryProvider = new DefaultRepository(new GetSet());
}
public function getRepository(string $name) {
return $this->repositoryProvider->getRepository($name);
}
public function __call() {
$this->repositoryProvider->__call();
}
}
In general I feel like the PHP community took a wild left turn, trying to be more like javascript and I feel that traits can walk you into a corner. This is a very good example of such a corner. I would really avoid them, at least for now. In the long run I believe Generics would be the better solution to your problem of needing a generic GetSet piece of code but generics haven't been implemented in php yet :-(.
I like to ask you about your practice of writing unit test, how to mock object and don't repeat the code?
I am using Symfony2 framework and for example I have many bundles with custom validators. When me and the rest of my team writing unit test we repeat the code of mocking Constraint, ExecutionContext, ConstraintViolationBuilderInterface. I know that we can create trait or abstract class or something else where we can store code responsible for mocking but before I will start doing this I like to know your best practices.
My first idea was to create a class/trait which will store for example mock of all repositories. Example:
class MockRepositoryHelper extends \PHPUnit_Framework_TestCase
{
public function getUserRepositoryMock()
{
return $this->prophesize(UserRepository::class);
}
// next repositories getters
}
and then use this code in real test case:
class EmailValidator extends \PHPUnit_Framework_TestCase
{
private $mockRepositoryHelper;
public function setUp()
{
parent::setUp();
$this->mockRepositoryHelper = new MockRepositoryHelper();
}
/**
* #test
*/
public function it_should_find_user()
{
$userRepository = $this->mockRepositoryHelper->getUserReposioryMock();
$userRepository->findUser(Argument::type('string'))->willReturn(null);
// rest of the test
}
}
Of course this is only pseudo code what I imagined, my first thought. What are yours ideas?
Basically I am asking how to write unit test faster and don't repeat the code?
I have a function that exists within a controller.
I want to that the logic is sound by writing a small unit test with assertions to match correctly with the output of the function.
I've created a new unit folder to house all the little unit tests for the controller. The correct term may be a functional test?
This is the current set up I have to house all of the assertions for the function. My question is, out of all the functions that exist in this external controller, how can I bring that function in and perform a test on the logic within it?
<?php
namespace Acme\SimplewanBundle\Tests\Unit;
use Doctrine\ORM\Tools\SchemaTool;
class ConfigControllerUnitTest extends \PHPUnit_Framework_TestCase {
public function testValidIpRange() {
}
}
First, the method should probably be moved to a service independent from the controller. In any case, without doing that change, you can already test the controller class as any other PHP class:
namespace Acme\SimplewanBundle\Tests\Unit;
use Doctrine\ORM\Tools\SchemaTool;
class ConfigControllerUnitTest extends \PHPUnit_Framework_TestCase {
public function testValidIpRange()
{
$controller = new \AppBundle\Controller\ConfigController();
$this->assertTrue($controller->isValidIpRange(...));
}
}
I am aware of the _bootstrap.php file that's used to set up the testing enviroment, etc., but I'm looking for a way to run some code after the entire test suite has finished.
Note that I'm not looking for a way to run code after a single class, i.e. something like _after, but after all classes.
Is there a way to achieve this?
Actually managed to solve this myself, here's how, if anyone is interested.
I created a new helper class inside _support.
<?php
class DataHelper extends \Codeception\Module
{
public function _beforeSuite()
{
// Set up before test suite
}
public function _afterSuite()
{
// Tear down after test suite
}
}
You can then enable this as a module in any suite configuration (the .yml files), like this:
modules:
enabled:
- DataHelper
#Sacha's solution is specially useful if you want to share the same methods accross all suites.
If you're looking for a way to define the methods for a specific suite (or if you want a different method per suite), you can define those methods directly in the suite Helper class.
For instance, if you want to define a _afterSuite method for the Acceptance Suite, just go to support/AcceptanceHelper.php and define those methods there. Eg:
<?php
namespace Codeception\Module;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class AcceptanceHelper extends \Codeception\Module
{
public function _afterSuite() {
die('everything done');
}
}