I'm trying to write unit tests for my code, but for some reason I can't get it to work. To simplify it, I have the following:
namespace Custom\Shipping\Model\Config\Source;
use Custom\Foundation\Model\Config\Source\AbstractSource;
use Custom\Shipping\Helper\Config;
/**
* Class ProductTypes
* @package Custom\Shipping\Model\Config\Source
*/
class ProductTypes extends AbstractSource
{
/**
* @var Config
*/
protected $configHelper;
/**
* ProductTypes constructor.
* @param Config $configHelper
*/
public function __construct(
Config $configHelper
)
{
$this->configHelper = $configHelper;
}
/**
* @return array
*/
public function toArray()
{
$returnValues = [];
$productTypes = $this->configHelper->getProductTypes();
foreach ($productTypes as $key => $value) {
$returnValues[$key] = $key;
}
return $returnValues;
}
}
Now, I want to mock the result of $this->configHelper->getProductTypes()
, so I set up my unit test like this:
namespace Custom\Shipping\Test\Unit\Model\Config\Source;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
/**
* Class ProductTypesTest
*/
class ProductTypesTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \Custom\Shipping\Model\Config\Source\ProductTypes
*/
protected $sourceModel;
/**
* @var \Custom\Shipping\Helper\Config|\PHPUnit_Framework_MockObject_MockObject
*/
protected $configHelperMock;
/**
* Set up before every test
*/
protected function setUp()
{
// Mock our config helper for this test:
$this->configHelperMock = $this->getMockBuilder('Custom\Shipping\Helper\Config')
->disableOriginalConstructor()
->getMock();
// Create our class to test:
$this->sourceModel = (new ObjectManager($this))
->getObject(
'Custom\Shipping\Model\Config\Source\ProductTypes',
[
'Config' => $this->configHelperMock
]
);
}
/**
* @param $productTypes
* @param $expectedResult
* @dataProvider toArrayDataProvider
*/
public function testToArray($productTypes, $expectedResult)
{
$this->configHelperMock
->method('getProductTypes')
->willReturn($productTypes);
$this->sourceModel->toArray();
// $this->assertEquals($expectedResult, $this->sourceModel->toArray());
}
/**
* @return array
*/
public function toArrayDataProvider()
{
return [
[['Foo' => 2.95, 'Bar' => 4.95], ['Foo' => 'Foo', 'Bar' => 'Bar']]
];
}
}
Now, as you can see in testToArray()
a tell my mock object to return the data from the data provider when getProductTypes()
is called.
However ... the return value is always NULL
.
The strange part is, that:
- When I do
$this->configHelperMock->getProductTypes()
in my test, it returns the correct result. - When I check with
get_class()
in my actual class I get the mocked object. - When I set
$this->configHelper->method('getProductTypes')->willReturn('foo')
in my actual class it returnsfoo
notNULL
(as expected). - When I move my constructing / creating of my mock object from
setUp
to my actual test it still returnsNULL
. - Even if I put everything in the test and don't use
setUp()
it still ... returns ... NULL:
This also doesn't work:
public function testToArray($productTypes, $expectedResult)
{
// Mock our config helper for this test:
$this->configHelperMock = $this->getMockBuilder('Custom\Shipping\Helper\Config')
->disableOriginalConstructor()
->getMock();
$this->configHelperMock
->method('getProductTypes')
->willReturn($productTypes);
// Create our class to test:
$this->sourceModel = (new ObjectManager($this))
->getObject(
'Custom\Shipping\Model\Config\Source\ProductTypes',
[
'Config' => $this->configHelperMock
]
);
$this->sourceModel->toArray();
// $this->assertEquals($expectedResult, $this->sourceModel->toArray());
}
So why can't I get it to work? I've used a similar approach on another (helper) class and that works just fine! This has been bugging me for a couple of hours now!
Any help is greatly appreciated.
EDIT: I included the source of Config
. No magic getters ....
namespace Custom\Shipping\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
/**
* Class Config
* @package Custom\Shipping\Helper
*/
class Config extends AbstractHelper
{
/**
* @return array
*/
public function getProductTypes()
{
$configValue = $this->scopeConfig->getValue('carriers/custom/product_types');
$returnValue = [];
$lines = explode("\n", $configValue);
foreach ($lines as $line) {
$line = trim($line);
if (!empty($line)) {
$arr = explode('::', $line);
if (count($arr) === 2) {
$returnValue[trim($arr[0])] = (float) $arr[1];
}
}
}
return $returnValue;
}
}