PHPUnit v.4+ mocking static methods - phpunit

I have following class with one method:
class A
{
public function my( $myParam )
{
\modelClass::truncateTable('table_name');
return $myParam * 4;
}
}
Is it possible to mock static method "truncateTable"? I want to make sure it was called once in "my" method. PHPUnit version 4.5, so "staticExpects" is no longer available in this version (depending this post).

You can use Proxy class that will wrap your static calls.
class ProxyModel{
public function truncateTable($tableName){
\modelClass::truncateTable($tableName);
}
}
After that in the Class that you are using the static call use your proxy class method instead.
class A{
private $model;
public function __construct(ProxyModel $model){
$this->model = $model;
}
public function my(){
$this->model->truncateModel("table_name");
}
}
Now you can easily mock the proxy class and pass it as dependency to your class.

Related

Why do actions with class and public method don't fire __construct()

I'm trying to understand how WordPress works with actions, classes, and methods.
If there is a class "TestClass" and it has a public method 'method1'
The method can be hooked to any action as "add_action('theHook', ['TestClass', 'method1']);"
From my understanding. If you don't initialize the class, you can not access its public methods and objects. Now, I would assume that WordPress has to follow this, and it must initialize my "TestClass", which will cause for public __construct() to fire.
However, after testing this, it does not fire __construct()..
Why is this?. I know a fix would be to self initialize inside 'method1', but I'm trying to figure out why WordPress behaves this way.
Because WordPress call your method as a static function: TestClass::method()
There is various solution:
1. Init class before add Action
Initialize your class before add action, like that:
$test = new TestClass();
add_action('hook', [$test, 'method']);
2. Call hook inside your Class:
class TestClass {
public function __construct() {
// Your construct
}
public function method() {
// Your Method
}
public function call_hook() {
add_action('hook', [$this, 'method']);
}
}
$test = new TestClass();
$test->call_hook();
3. Use a singleton
And if you need to to have only one instance of your class and call it in various place, you have to take a look to Singleton design pattern.
Demonstration:
class MySingletonClass {
private static $__instance = null;
private $count = 0;
private function __construct() {
// construct
}
public static function getInstance() {
if (is_null(self::$__instance)) {
self::$__instance = new MySingletonClass();
}
return self::$__instance;
}
public function method() {
$this->count += 1;
error_log("count:".$this->count);
}
}
$singleton = MySingletonClass::getInstance();
add_action('wp_head', [$singleton, 'method']);
$singleton2 = MySingletonClass::getInstance();
add_action('wp_footer', [$singleton2, 'method']);

BaseController to handle client factory

I want to build a base controller that I can put some reusable methods so I do not have to put a bunch of repeat code in all my controllers. So I built a BaseController.cs
public class BaseController : Controller
{
public IHttpClientFactory _clientFactory;
public BaseController(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
}
Then in one of my contollers I do public class TokenController : BaseController. But then it wants me to add the following but then it gives me errors
public TokenController(IHttpClientFactory clientFactory)
{
// I guess something goes here
}
But then VS Code tells me
There is no argument given that corresponds to the required formal parameter 'clientFactory' of 'BaseController.BaseController(IHttpClientFactory)' (CS7036)
What am I missing here? I been in JS world to long :)
When inheriting classes without default constructors you have to pass parameters to them using the following syntax:
public TokenController(IHttpClientFactory clientFactory) : base (clientFactory)
{
/* other initializations */
}
So add the following expression: : base (clientFactory)
See more information here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors

How do I pass an id variable to a class which has dependency injection Symfony 3.4

I have class that uses Dependency Injection, with two other classes, this works fine. But I want to then instantiate the Merchant class in a controller and pass an id . Thing I don't get is the constructor is expecting more values 'CurrencyConverter' and 'TransactionTable' so how can I complete the code ? ?, which I don't need to pass. So I'm not clear how to make it work, thanks
Model Class
namespace TransactionBundle\Model;
class Merchant
{
public $_transactions;
public $_currencyConverter;
public $_id;
public function __construct($id,CurrencyConverter
$currencyConverter,TransactionTable $transactions)
{
$this->_transactions = $transactions;
$this->_currencyConverter = $currencyConverter;
$this->_id = $id;
}
public function getTransactions() {
$this->_currencyConverter->convert();
$this->_transactions->getData();
}
}
trying to instantiate in the controller
$merchant = new Merchant(2,?,?);
$results = $merchant->getTransactions();
If the class has a dependency on something that is not in the container, then the class cannot be loaded from the container.
Either pass the dependencies yourself in the controller:
$merchant = new Merchant(2, $currencyConverter, $transactions);
Or use a factory service in the container:
class MerchantFactory {
private $currencyConverter;
private $transactions;
// constructor omitted for brevity
public function getMerchantForId($id) {
return new Merchant($id, $this->currencyConverter, $this->transactions);
}
}
Then in your controller, depend on the factory:
$merchant = $this->merchantFactory->getMerchantForId(2);

Undefined variable in PHPUnit Test Class

I have a test class that reports an undefined variable and I cannot seem to understand what the issue is.
Basically the listener below is suppose to listen to an application boot event documented in the class below:
<?php
namespace Colleen\Core\Event\Application;
final class ApplicationBootedEvents
{
const APP_BOOTED = 'application.booted';
}
My event class is as shown below which receives an instance of the application itself.
<?php
namespace Colleen\Core\Event\Application;
use Symfony\Component\EventDispatcher\Event;
use Colleen\Core\Application;
/**
* The application.booted event is dispatched each time
* an application instance is created in the system.
*
*/
class ApplicationBootedEvent extends Event
{
protected $app;
public function __construct(Application $app)
{
$this->app = $app;
}
public function getApplication()
{
return $app;
}
}
These two classes to me look perfect according to Symfony's documentation on the Event Dispatcher Component. Following is the listener class that is suppose to listen to ApplicationBootedEvents::APP_BOOTED event.
<?php
namespace Colleen\Core\Event\Application\Listener;
use Colleen\Core\Event\Application\ApplicationBootedEvent;
class ApplicationBootedListener
{
public function onBoot(ApplicationBootedEvent $event)
{
$container = $event->getApplication()->getContainer();
$container->set('class.dispatcher', '\\Symfony\\Component\\EventDispatcher\\EventDispatcher');
}
}
The Listener class does nothing at the moment and my test case is to test whether the "class.dispatcher" key exist on my container which simple extends Pimple and is made available through the Application Object.
Below is my test that shows how these will eventually be used in my front controller or any class that stands between them and the front controller.
<?php
namespace Colleen\Qa\Core\Event\Application\Listener;
use Colleen\Core\Event\Application\Listener\ApplicationBootedListener;
use Colleen\Core\Event\Application\ApplicationBootedEvents;
use Colleen\Core\Event\Application\ApplicationBootedEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Colleen\Core\Container\Container;
use Colleen\Core\Application;
class AppliocationBootedListenerTest extends \PHPUnit_Framework_TestCase
{
public function testApplicationBootListener()
{
$dispatcher = new EventDispatcher();
$dispatcher->addListener(
ApplicationBootedEvents::APP_BOOTED, array(
new ApplicationBootedListener(), 'onBoot'
));
$app = $dispatcher->dispatch(ApplicationBootedEvents::APP_BOOTED, new ApplicationBootedEvent(new Application(new Container())))->getApplication();
$expected = '\\Symfony\\Component\\EventDispatcher\\EventDispatcher';
$actual = $app->getContainer()->get('class.dispatcher');
$this->assertSame($expected, $actual);
}
}
The idea is to test whether the Listener gets called and if it is able to feed our application object's container with all the necesary objects we will need to get our web framework to work.
Below is the output I get as a result if running this test case.
There's an error in your ApplicationBootedEvent.php file, on line 24 as the stack trace suggested..
Change
public function getApplication()
{
return $app;
}
To
public function getApplication()
{
return $this->app;
}

Access to symfony services in Behat extension

I'm writing a Behat extension meant to be used with Symfony and Symfony2Extension.
For some services, I need to inject services defined in the Symfony application. Is there a way to do that?
In your FeatureContext.php file, you need to implement KernelAwareInterface and define setKernel() method. Methods getParameter() and getService() are option and for demonstration purposes.
Example
namespace Football\TeamBundle\Features\Context;
use Behat\MinkExtension\Context\MinkContext;
use Behat\Symfony2Extension\Context\KernelAwareInterface;
use Symfony\Component\HttpKernel\KernelInterface;
class FeatureContext extends MinkContext implements KernelAwareInterface
{
private $kernel;
public function setKernel(KernelInterface $kernelInterface)
{
$this->kernel = $kernelInterface;
}
public function getParameter()
{
$myParameter = $this->kernel->getContainer()->getParameter('name_of_the_param');
}
public function getService()
{
$myService = $this->kernel->getContainer()->get('name_of_the_service');
}
}

Resources