How to share objects in different test in PHPUnit - php

I have the following class 'MyControllerTest' for testing purposes of 'MyController'.
I want to share the same object which is '$algorithms' in different tests of this classes but I don't know how to do that after trying adding the variable in different places:
class MyControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
// $algorithms = ... <----- does not work
public static function main()
{
$suite = new PHPUnit_Framework_TestSuite("MyControllerTest");
$result = PHPUnit_TextUI_TestRunner::run($suite);
}
public function setUp()
{
$this->bootstrap = new Zend_Application(
'testing',
APPLICATION_PATH . '/configs/application.ini'
);
$configuration = Zend_Registry::get('configuration');
// $algorithms = ... <----- does not work
parent::setUp();
}
public function tearDown()
{
}
public function test1() {
// this array shared in different tests
$algorithms[0] = array(
"class" => "Mobile",
"singleton" => "true",
"params" => array(
"mobile" => "true",
"phone" => "false"
)
);
...
}
public function test2() { };
}
How can I share this object?
Any help would be appreciated!

You've got a couple of options here
Declare the data fixture right into the setUp method and declare a private variable that holds it. So you can use it in the other test methods.
Declare a private function within your test class that holds your data fixture. If you need the data fixture just call the private method
Create a Utiltity class with a method that holds the data fixture. The Utility class is initialized in the setUp function. Declare a private variable within the MyControllerTest that holds the instance of the Utility class. When a test needs the fixture just call the fixture method from the Utility instance.
Example 1
class MyControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
private $alg;
public function setUp()
{
# variable that holds the data fixture
$this->alg = array(....);
}
public function test1()
{
$this->assertCount(1, $this->alg);
}
}
Example 2
class MyControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public function test1()
{
$this->assertCount(1, $this->getAlgo());
}
# Function that holds the data fixture
private function getAlgo()
{
return array(....);
}
}
Example 3
class Utility
{
# Function that holds the data fixture
public function getAlgo()
{
return array(....);
}
}
class MyControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
private $utility;
public function setUp()
{
$this->utility = new Utility();
}
public function test1()
{
$this->assertCount(1, $this->utility->getAlgo());
}
}
But beware of fixtures that are shared and are altered in some tests. This can really mess up your test suite.

Related

Access protected properties via public method

I'm testing a logic flow by mocking a class and testing for the function call.
function() setUp()
{
$this->shipping_method = $this->getMockBuilder(Wc_Trincargo_Shipping_Method::class)
->getMock();
$this->shipping_method->set_post_data([
'woocommerce_wc-trinicargo-shipping_waybill_password' => 'xxx',
'woocommerce_wc-trinicargo-shipping_waybill_username' => 'xxxx',
'woocommerce_wc-trinicargo-shipping_waybill_customer_id' => uniqid(),
'woocommerce_wc-trinicargo-shipping_waybill_pickupdays' => 2
]);
}
set_post_data is a public method that sets a protected property.
Later down I test to call a another method that needs to check the said protected property. I know they say you can't mock protected and private properties but if the properties are being set by public methods....shouldn't it work?
If you really need to access a protected property within a test and you don't have a getter (nor should you create one purely for a test), you could use reflection.
<?php
class MyClass
{
protected $myProperty;
public function setMyProperty($value)
{
$this->myProperty = $value;
}
}
$a = new MyClass();
$a->setMyProperty('TestValue');
// echo $a->myProperty; Can't do this because it's protected.
$r = new ReflectionProperty('MyClass', 'myProperty');
$r->setAccessible(true);
$value = $r->getValue($a);
echo $value; // 'TestValue'
It is irrelevant that the protected property was sat from a public method. The visibility belongs to the property regardless. If you need to check the value of the property afterwards, create a public getter for that property.
Note that it is useless to test simple getters and setters. You should test what the class does with the values of the properties instead.
Example of a useless test:
class MyClass {
private $prop;
public function setProp($value) {
$this->prop = $value;
}
public function getProp() {
return $this->prop;
}
}
Test
$myClass = new MyClass();
$myClass->setProp('foo');
assertTrue($myClass->getProp() === 'foo');
Example of a class that uses a prop in a meaningful way, which determines the behavior/output of another method:
class MyClass2 {
private $prop;
public function setProp($value) {
$this->prop = $value;
}
public function getPropUpperCase() {
return strtoupper($this->prop);
}
}
Test
$myClass2 = new MyClass();
$myClass2->setProp('foo');
assertTrue($myClass->getPropUpperCase() === 'FOO');

Unit test returning injected object

I have a basic class which I inject into another class
AClass
{
protected $thing;
public function setThing($thing)
{
$this->thing = $thing;
}
public function getThing()
{
return $this->thing;
}
}
This class is the SUT.
AnotherClass
{
protected $aClass;
protected $someOtherClass;
__construct(AClass $aClass, SomeOtherClass $someOtherClass)
{
$this->aClass = $aClass;
$this->someOtherClass = $someOtherClass;
}
public function thatImTesting()
{
...
$thing = "logic from {$this->someOtherClass} and some other stuff";
return $this->aClass->setThing($thing);
}
}
So I want to test AnotherClass so I mock SomeOtherClass and inject it into the SUT. However, I create a new AClass and inject it in because I don't want to mock the functions (as that would make no sense).
$someOtherClassMock = m::mock(SomeOtherClass::class, [
// mocking the functions here
]);
$aClass = new AClass();
$anotherClass = new AnotherClass($aClass, $someOtherClassMock);
$this->assertEquals('Something', $anotherClass->getThing());
As $anotherClass object is returned and I need to call a function to check the data in the test, is this still a unit test?

PHPUnit: include class after mocking it

I'm happily writing unit tests, but they clash when I run them all together. I'm testing this class:
class MyClass {
public function sayHello() {
return 'Hello world';
}
}
using this test. All tests have a structure like this:
class MyClassTest extends PHPUnit_Framework_TestCase {
private $subject;
public static function setUpBeforeClass() {
require_once('path/to/MyClass.php');
}
public function setUp() {
$this->subject = new MyClass();
}
public function testSayHello() {
$this->assertEquals('Hello world', $this->subject->sayHello());
}
}
MyClassTest runs fine on its own. But PHPUnit will crash because I redeclare the class, if another test mocks MyClass and happens to run first:
class Inject {
private $dependency;
public function __construct(MyClass $myClass) {
$this->dependency = $myClass;
}
public function printGreetings() {
return $this->dependency->sayHello();
}
}
class InjectTest extends PHPUnit_Framework_TestCase {
public function testPrintGreetings() {
$myClassMock = $this
->getMockBuilder('MyClass')
->setMethods(array('sayHello'))
->getMock();
$myClassMock
->expects($this->once())
->method('sayHello')
->will($this->returnValue(TRUE));
$subject = new Inject($myClassMock);
$this->assertEquals('Hello world', $subject->printGreetings());
}
}
I do use a bootstrap.php to fake some global functions not yet refactored.
I have no auto loaders and don't want to process-isolate EVERY test, because it takes forever. I tried inserting combinations #runTestsInSeparateProcesses and #preserveGlobalState enabled/disabled in the docblocks of both Test 1 & 2, I still get the same error.
To understand this behaviour, you need to have a look at how PHPUnit works. getMockBuilder()->getMock(), dynamically creates the following code for the mock class:
class Mock_MyClass_2568ab4c extends MyClass implements PHPUnit_Framework_MockObject_MockObject
{
private static $__phpunit_staticInvocationMocker;
private $__phpunit_invocationMocker;
public function __clone()
{
$this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();
}
public function sayHello()
{
$arguments = array();
$count = func_num_args();
if ($count > 0) {
$_arguments = func_get_ ...
# more lines follow ...
If MyClass hasn't already been loaded at this time, it adds the following dummy declaration:
class MyClass
{
}
This code will then getting parsed using eval() (!).
Since PHPUnit will execute InjectTest before MyClassTest, this means that the mock builder will define the dummy class and MyClass is already defined when MyClassTest::setUpBeforeClass will get called. That's why the error. I hope I could explain. Otherwise, dig into PHPUnit's code.
Solution:
Drop the setUpBeforeClass() method and put the require_once statement on top of the tests. setUpBeforeClass() is not meant for including classes. Refer to the docs.
Btw, having require_once on top will work because PHPUnit will include every test file before starting the first test.
tests/MyClassTest.php
require_once __DIR__ . '/../src/MyClass.php';
class MyClassTest extends PHPUnit_Framework_TestCase {
private $subject;
public function setUp() {
$this->subject = new MyClass();
}
public function testSayHello() {
$this->assertEquals('Hello world', $this->subject->sayHello());
}
}
tests/InjectTest.php
require_once __DIR__ . '/../src/Inject.php';
class InjectTest extends PHPUnit_Framework_TestCase {
public function testPrintGreetings() {
$myClassMock = $this
->getMockBuilder('MyClass')
->setMethods(array('sayHello'))
->getMock();
$myClassMock
->expects($this->once())
->method('sayHello')
->will($this->returnValue(TRUE));
$subject = new Inject($myClassMock);
$this->assertEquals(TRUE, $subject->printGreetings());
}
}

OOP Access to protected property with getX( ) with inheritance

I try to access to a protected property with inheritance class but when I get my value property with $this->getContainer(), I got NULL value and I don't know why ...
I very simplified my code :
<?php
abstract class Kernel
{
protected $container;
public function __construct() {
$this->setContainer(['config' => 'OK']);
}
public function setContainer($array) {
$this->container = $array;
}
public function getContainer() {
return $this->container;
}
}
class AppKernel extends Kernel {
}
class FrontController extends AppKernel
{
public function __construct() {
var_dump($this->getContainer());
}
}
// Init
$kernel = new AppKernel();
$FrontController = new FrontController();
Normaly, when I call new FrontController, it should print my array in my protected property, but i got NULL.
Someone can help me please ?
Thanks!
you are overriding the default constrcuctor.
add parent::__construct to the front controller constructor

Magento - UnitTests - Mock Objects

I am writing some tests for a Magento module, using Ivan Chepurnyi's extension, and I'm having trouble using the mock objects.
Here is the class:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
public function __construct()
{
$this->_salesCollection = Mage::getModel('module/classA')->getCollection()
->addFieldToFilter('id', $this->_getId());
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_salesCollection->count();
}
}
The method I'm trying to test is getSalesTotalNumber().
And here is the test:
<?php
class Namespace_Module_Test_Block_Class extends EcomDev_PHPUnit_Test_Case
{
private $_mock;
public function setUp()
{
$this->_mock = $this->getMock('Namespace_Module_Block_Class',
array('_getId')
);
$this->_mock->expects($this->any())
->method('_getId')
->will($this->returnValue(1024));
parent::setUp();
}
/**
* #test
* #loadFixture
* #loadExpectation
*/
public function testSalesTotalNumber()
{
$actual = $this->_mock->getSalesTotalValue();
$expected = $this->_getExpectations()->getSalesTotalNumber();
$this->assertEquals($expected, $actual);
}
}
As you can see, what I want to do is overwrite the _getId() method so that it returns an id which match the id in the fixture and so load the collection. But it doesn't work :-(.
In my test, if I echo $this->_mock->_getId() it returns the correct Id (1024). But in the __construct() of my class $this->_getId() returns null, which is the expected value during testing (I mean, during testing there is no session, so it can't get the object's Id as I store it in a session variable). So the _getId() method isn't mocked by my test case.
Any help will be highly appreciated.
So my problem was not in the mock/test but in the class.
I have moved the content of __construct() into a protected method which returns the collection object. That's how my class looks like now:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
protected function _getAffiliateSales()
{
if (is_null($this->_salesCollection)) {
$affiliateId = $this->_getId();
$this->_salesCollection = Mage::getModel('module/classA')
->addFieldToFilter('id', $affiliateId);
}
return $this->_salesCollection;
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_getAffiliateSales()->count();
}
}

Categories