add tests, improve code

This commit is contained in:
Daniel Seifert 2022-12-26 00:20:16 +01:00
parent bf77b65ad5
commit 506bbd648e
Signed by: DanielS
GPG Key ID: 6A513E13AEE66170
6 changed files with 682 additions and 31 deletions

View File

@ -21,13 +21,19 @@ use D3\Linkmobility4OXID\Application\Model\MessageTypes\Sms;
use D3\Linkmobility4OXID\Application\Model\OrderRecipients; use D3\Linkmobility4OXID\Application\Model\OrderRecipients;
use D3\LinkmobilityClient\Response\ResponseInterface; use D3\LinkmobilityClient\Response\ResponseInterface;
use D3\LinkmobilityClient\ValueObject\Recipient; use D3\LinkmobilityClient\ValueObject\Recipient;
use Exception; use D3\TestingTools\Production\IsMockable;
use InvalidArgumentException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminController; use OxidEsales\Eshop\Application\Controller\Admin\AdminController;
use OxidEsales\Eshop\Application\Model\Order; use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Language;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Request;
use OxidEsales\Eshop\Core\UtilsView;
class AdminOrder extends AdminController class AdminOrder extends AdminController
{ {
use IsMockable;
protected $_sThisTemplate = 'd3adminorder.tpl'; protected $_sThisTemplate = 'd3adminorder.tpl';
/** /**
@ -42,12 +48,13 @@ class AdminOrder extends AdminController
public function __construct() public function __construct()
{ {
$this->order = $order = oxNew(Order::class); $this->order = $order = $this->d3GetMockableOxNewObject(Order::class);
$order->load($this->getEditObjectId()); $order->load($this->getEditObjectId());
$this->addTplParam('recipient', $this->getRecipientFromCurrentOrder()); $this->addTplParam('recipient', $this->getRecipientFromCurrentOrder());
parent::__construct(); parent::__construct();
} }
/** /**
@ -56,48 +63,82 @@ class AdminOrder extends AdminController
public function getRecipientFromCurrentOrder() public function getRecipientFromCurrentOrder()
{ {
try { try {
return oxNew(OrderRecipients::class, $this->order)->getSmsRecipient(); return $this->d3GetMockableOxNewObject(OrderRecipients::class, $this->order)->getSmsRecipient();
} catch (noRecipientFoundException $e) { } catch (noRecipientFoundException $e) {
/** @var string $message */ /** @var string $message */
$message = Registry::getLang()->translateString($e->getMessage()); $message = $this->d3GetMockableRegistryObject(Language::class)->translateString($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($message); $this->d3GetMockableRegistryObject(UtilsView::class)->addErrorToDisplay($message);
} }
return false; return false;
} }
/** /**
* @return void * @return void
* @throws Exception
*/ */
public function send(): void public function send(): void
{ {
$messageBody = Registry::getRequest()->getRequestEscapedParameter('messagebody'); $utilsView = $this->d3GetMockableRegistryObject(UtilsView::class);
if (false === is_string($messageBody) || strlen($messageBody) <= 1) {
/** @var string $message */
$message = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_NO_LENGTH');
Registry::getUtilsView()->addErrorToDisplay($message);
return;
}
$order = oxNew(Order::class);
$order->load($this->getEditObjectId());
try { try {
$sms = oxNew(Sms::class, $messageBody); $utilsView->addErrorToDisplay($this->sendMessage());
if ($sms->sendOrderMessage($order)) { } catch (noRecipientFoundException|InvalidArgumentException $e) {
$smsCount = $sms->getResponse() ? $sms->getResponse()->getSmsCount() : 0; $utilsView->addErrorToDisplay($e);
Registry::getUtilsView()->addErrorToDisplay(
oxNew(successfullySentException::class, $smsCount)
);
} else {
$errorMsg = $sms->getResponse() instanceof ResponseInterface ? $sms->getResponse()->getErrorMessage() : 'no response';
/** @var string $format */
$format = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_UNEXPECTED_ERR_SEND');
Registry::getUtilsView()->addErrorToDisplay(sprintf($format, $errorMsg));
}
} catch (noRecipientFoundException $e) {
Registry::getUtilsView()->addErrorToDisplay($e);
} }
} }
/**
* @return string
* @throws InvalidArgumentException
*/
protected function getMessageBody(): string
{
$messageBody = $this->d3GetMockableRegistryObject(Request::class)
->getRequestEscapedParameter('messagebody');
if (false === is_string($messageBody) || strlen(trim($messageBody)) <= 1) {
throw $this->d3GetMockableOxNewObject(
InvalidArgumentException::class,
Registry::getLang()->translateString('D3LM_EXC_MESSAGE_NO_LENGTH')
);
}
return $messageBody;
}
/**
* @return string
* @throws noRecipientFoundException
*/
protected function sendMessage(): string
{
$order = $this->d3GetMockableOxNewObject(Order::class);
$order->load($this->getEditObjectId());
$sms = $this->d3GetMockableOxNewObject(Sms::class, $this->getMessageBody());
return $sms->sendOrderMessage($order) ?
(string) $this->getSuccessSentMessage($sms) :
$this->getUnsuccessfullySentMessage($sms);
}
/**
* @param Sms $sms
* @return successfullySentException
*/
protected function getSuccessSentMessage(Sms $sms): successfullySentException
{
$smsCount = $sms->getResponse() ? $sms->getResponse()->getSmsCount() : 0;
return $this->d3GetMockableOxNewObject(successfullySentException::class, $smsCount);
}
/**
* @param Sms $sms
* @return string
*/
protected function getUnsuccessfullySentMessage(Sms $sms): string
{
$errorMsg = $sms->getResponse() instanceof ResponseInterface ? $sms->getResponse()->getErrorMessage() : 'no response';
/** @var string $format */
$format = Registry::getLang()->translateString('D3LM_EXC_MESSAGE_UNEXPECTED_ERR_SEND');
return sprintf($format, $errorMsg);
}
} }

2
src/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.phpunit.result.cache
reports

52
src/tests/README.md Normal file
View File

@ -0,0 +1,52 @@
# D3 Linkmobility4OXID Tests
## Requirements
Both unit and acceptance tests require OXID Testing Library installed.
See https://github.com/OXID-eSales/testing_library.
### Configuration
Please install the packages listed in the composer.json in "require-dev". Unfortunately Composer does not provide an automatic installation.
Here is an example of Testing Library configuration file `oxideshop/test_config.yml`
```
# This file is auto-generated during the composer install
mandatory_parameters:
shop_path: /var/www/oxideshop/source
shop_tests_path: /var/www/oxideshop/tests
partial_module_paths: d3/linkmobility
optional_parameters:
shop_url: null
shop_serial: ''
enable_varnish: false
is_subshop: false
install_shop: false
remote_server_dir: null
shop_setup_path: null
restore_shop_after_tests_suite: false
test_database_name: null
restore_after_acceptance_tests: false
restore_after_unit_tests: false
tmp_path: /tmp/oxid_test_library/
database_restoration_class: DatabaseRestorer
activate_all_modules: false
run_tests_for_shop: false
run_tests_for_modules: true
screen_shots_path: null
screen_shots_url: null
browser_name: firefox
selenium_server_ip: 127.0.0.1
selenium_server_port: '4444'
additional_test_paths: null
```
## Unit Tests
To execute unit tests run the following:
```
cd /var/www/oxideshop/
PHPBIN=/usr/bin/php7.4 ./vendor/bin/runtests
```

View File

@ -0,0 +1,25 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\Linkmobility4OXID\tests;
use D3\ModCfg\Tests\additional_abstract;
use OxidEsales\Eshop\Core\Exception\StandardException;
class additional extends additional_abstract
{
}
oxNew(additional::class);

28
src/tests/phpunit.xml Normal file
View File

@ -0,0 +1,28 @@
<phpunit backupGlobals="true"
backupStaticAttributes="false"
cacheTokens="true"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="false"
convertWarningsToExceptions="true"
forceCoversAnnotation="false"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
verbose="false">
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">../Application</directory>
<directory suffix=".php">../Modules</directory>
<directory suffix=".php">../Setup</directory>
<exclude>
<directory suffix=".php">../Application/views</directory>
</exclude>
</whitelist>
</filter>
<logging>
<log type="junit" target="reports/logfile.xml"/>
</logging>
</phpunit>

View File

@ -0,0 +1,503 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\Linkmobility4OXID\tests\unit\Application\Controller\Admin;
use D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder;
use D3\Linkmobility4OXID\Application\Model\Exceptions\noRecipientFoundException;
use D3\Linkmobility4OXID\Application\Model\Exceptions\successfullySentException;
use D3\Linkmobility4OXID\Application\Model\MessageTypes\Sms;
use D3\Linkmobility4OXID\Application\Model\OrderRecipients;
use D3\LinkmobilityClient\SMS\Response;
use D3\LinkmobilityClient\ValueObject\Recipient;
use D3\TestingTools\Development\CanAccessRestricted;
use InvalidArgumentException;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Request;
use OxidEsales\Eshop\Core\UtilsView;
use OxidEsales\TestingLibrary\UnitTestCase;
use PHPUnit\Framework\MockObject\MockObject;
use ReflectionException;
class AdminOrderTest extends UnitTestCase
{
use CanAccessRestricted;
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::__construct
*/
public function canConstruct()
{
/** @var Order|MockObject $orderMock */
$orderMock = $this->getMockBuilder(Order::class)
->onlyMethods(['load'])
->getMock();
$orderMock->method('load')->willReturn(true);
/** @var Recipient|MockObject $recipientMock */
$recipientMock = $this->getMockBuilder(Recipient::class)
->disableOriginalConstructor()
->getMock();
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->disableOriginalConstructor()
->onlyMethods(['d3GetMockableOxNewObject', 'getEditObjectId', 'getRecipientFromCurrentOrder'])
->getMock();
$sut->method('d3GetMockableOxNewObject')->willReturnCallback(
function () use ($orderMock) {
$args = func_get_args();
switch ($args[0]) {
case Order::class:
return $orderMock;
default:
return call_user_func_array("oxNew", $args);
}
}
);
$sut->method('getEditObjectId')->willReturn('editObjId');
$sut->method('getRecipientFromCurrentOrder')->willReturn($recipientMock);
$this->callMethod(
$sut,
'__construct'
);
$this->assertSame(
$orderMock,
$this->getValue(
$sut,
'order'
)
);
$this->assertSame(
$recipientMock,
$this->callMethod(
$sut,
'getViewDataElement',
['recipient']
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::getRecipientFromCurrentOrder
*/
public function canGetRecipientFromCurrentOrderPassed()
{
/** @var Recipient|MockObject $recipientMock */
$recipientMock = $this->getMockBuilder(Recipient::class)
->disableOriginalConstructor()
->getMock();
/** @var OrderRecipients|MockObject $orderRecipientsMock */
$orderRecipientsMock = $this->getMockBuilder(OrderRecipients::class)
->disableOriginalConstructor()
->onlyMethods(['getSmsRecipient'])
->getMock();
$orderRecipientsMock->method('getSmsRecipient')->willReturn($recipientMock);
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->onlyMethods(['d3GetMockableOxNewObject'])
->disableOriginalConstructor()
->getMock();
$sut->method('d3GetMockableOxNewObject')->willReturnCallback(
function () use ($orderRecipientsMock) {
$args = func_get_args();
switch ($args[0]) {
case OrderRecipients::class:
return $orderRecipientsMock;
default:
return call_user_func_array("oxNew", $args);
}
}
);
$this->setValue(
$sut,
'order',
oxNew(Order::class)
);
$this->assertSame(
$recipientMock,
$this->callMethod(
$sut,
'getRecipientFromCurrentOrder'
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::getRecipientFromCurrentOrder
*/
public function canGetRecipientFromCurrentOrderThrowsException()
{
/** @var UtilsView|MockObject $utilsViewMock */
$utilsViewMock = $this->getMockBuilder(UtilsView::class)
->onlyMethods(['addErrorToDisplay'])
->getMock();
$utilsViewMock->expects($this->once())->method('addErrorToDisplay');
/** @var OrderRecipients|MockObject $orderRecipientsMock */
$orderRecipientsMock = $this->getMockBuilder(OrderRecipients::class)
->disableOriginalConstructor()
->onlyMethods(['getSmsRecipient'])
->getMock();
$orderRecipientsMock->method('getSmsRecipient')->willThrowException(
oxNew(noRecipientFoundException::class)
);
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->onlyMethods(['d3GetMockableOxNewObject', 'd3GetMockableRegistryObject'])
->disableOriginalConstructor()
->getMock();
$sut->method('d3GetMockableOxNewObject')->willReturnCallback(
function () use ($orderRecipientsMock) {
$args = func_get_args();
switch ($args[0]) {
case OrderRecipients::class:
return $orderRecipientsMock;
default:
return call_user_func_array("oxNew", $args);
}
}
);
$sut->method('d3GetMockableRegistryObject')->willReturnCallback(
function () use ($utilsViewMock) {
$args = func_get_args();
switch ($args[0]) {
case UtilsView::class:
return $utilsViewMock;
default:
return Registry::get($args[0]);
}
}
);
$this->setValue(
$sut,
'order',
oxNew(Order::class)
);
$this->assertFalse(
$this->callMethod(
$sut,
'getRecipientFromCurrentOrder'
)
);
}
/**
* @test
* @param $throwsException
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::send
* @dataProvider canSendDataProvider
*/
public function canSend($throwsException)
{
/** @var UtilsView|MockObject $utilsViewMock */
$utilsViewMock = $this->getMockBuilder(UtilsView::class)
->onlyMethods(['addErrorToDisplay'])
->getMock();
$utilsViewMock->expects($this->once())->method('addErrorToDisplay');
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->onlyMethods(['d3GetMockableRegistryObject', 'sendMessage'])
->disableOriginalConstructor()
->getMock();
$sut->method('d3GetMockableRegistryObject')->willReturnCallback(
function () use ($utilsViewMock) {
$args = func_get_args();
switch ($args[0]) {
case UtilsView::class:
return $utilsViewMock;
default:
return Registry::get($args[0]);
}
}
);
$sut->method('sendMessage')->will(
$throwsException ?
$this->throwException(oxNew(noRecipientFoundException::class)) :
$this->returnValue('successfully sent message')
);
$this->callMethod(
$sut,
'send'
);
}
/**
* @return array
*/
public function canSendDataProvider(): array
{
return [
'can send message' => [false],
'can not send message' => [true],
];
}
/**
* @param $message
* @param $expectException
* @param $expected
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::getMessageBody
* @dataProvider canGetMessageBodyDataProvider
*/
public function canGetMessageBody($message, $expectException, $expected)
{
/** @var Request|MockObject $requestMock */
$requestMock = $this->getMockBuilder(Request::class)
->onlyMethods(['getRequestEscapedParameter'])
->getMock();
$requestMock->method('getRequestEscapedParameter')->willReturn($message);
/** @var Request|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->onlyMethods(['d3GetMockableRegistryObject'])
->disableOriginalConstructor()
->getMock();
$sut->method('d3GetMockableRegistryObject')->willReturnCallback(
function () use ($requestMock) {
$args = func_get_args();
switch ($args[0]) {
case Request::class:
return $requestMock;
default:
return Registry::get($args[0]);
}
}
);
if ($expectException) {
$this->expectException(InvalidArgumentException::class);
}
$this->assertSame(
$expected,
$this->callMethod(
$sut,
'getMessageBody'
)
);
}
/**
* @return array[]
*/
public function canGetMessageBodyDataProvider(): array
{
return [
'message not string' => [[], true, ''],
'message empty string' => ['', true, ''],
'message whitespace string' => [' ', true, ''],
'message right string' => ['messagefixture', false, 'messagefixture'],
];
}
/**
* @test
* @param $canSendOrderMessage
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::sendMessage
* @dataProvider canSendMessageDataProvider
*/
public function canSendMessage($canSendOrderMessage)
{
/** @var Order|MockObject $orderMock */
$orderMock = $this->getMockBuilder(Order::class)
->onlyMethods(['load'])
->getMock();
$orderMock->method('load')->willReturn(true);
/** @var Sms|MockObject $smsMock */
$smsMock = $this->getMockBuilder(Sms::class)
->disableOriginalConstructor()
->onlyMethods(['sendOrderMessage'])
->getMock();
$smsMock->expects($this->once())->method('sendOrderMessage')->willReturn($canSendOrderMessage);
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->disableOriginalConstructor()
->onlyMethods(['d3GetMockableOxNewObject', 'getMessageBody', 'getSuccessSentMessage', 'getUnsuccessfullySentMessage'])
->getMock();
$sut->method('d3GetMockableOxNewObject')->willReturnCallback(
function () use ($orderMock, $smsMock) {
$args = func_get_args();
switch ($args[0]) {
case Order::class:
return $orderMock;
case Sms::class:
return $smsMock;
default:
return call_user_func_array("oxNew", $args);
}
}
);
$sut->method('getMessageBody')->willReturn('messageBodyFixture');
$sut->expects($this->exactly((int) $canSendOrderMessage))->method('getSuccessSentMessage')
->willReturn(oxNew(successfullySentException::class, 'expectedReturn'));
$sut->expects($this->exactly((int) !$canSendOrderMessage))->method('getUnsuccessfullySentMessage')
->willReturn('expectedReturn');
$this->assertIsString(
$this->callMethod(
$sut,
'sendMessage'
)
);
}
/**
* @return array
*/
public function canSendMessageDataProvider(): array
{
return [
'send order message' => [true],
'dont send order message' => [false]
];
}
/**
* @test
* @param $hasResponse
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::getSuccessSentMessage
* @dataProvider canGetSuccessSentMessageDataProvider
*/
public function canGetSuccessSentMessage($hasResponse)
{
/** @var successfullySentException|MockObject $successfullySendExceptionMock */
$successfullySendExceptionMock = $this->getMockBuilder(successfullySentException::class)
->disableOriginalConstructor()
->getMock();
/** @var Response|MockObject $resonseMock */
$resonseMock = $this->getMockBuilder(Response::class)
->onlyMethods(['getSmsCount'])
->disableOriginalConstructor()
->getMock();
$resonseMock->expects($hasResponse ? $this->once() : $this->never())->method('getSmsCount')
->willReturn(20);
/** @var Sms|MockObject $smsMock */
$smsMock = $this->getMockBuilder(Sms::class)
->disableOriginalConstructor()
->onlyMethods(['getResponse'])
->getMock();
$smsMock->method('getResponse')->willReturn($hasResponse ? $resonseMock : null);
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->disableOriginalConstructor()
->onlyMethods(['d3GetMockableOxNewObject'])
->getMock();
$sut->method('d3GetMockableOxNewObject')->willReturnCallback(
function () use ($successfullySendExceptionMock) {
$args = func_get_args();
switch ($args[0]) {
case successfullySentException::class:
return $successfullySendExceptionMock;
default:
return call_user_func_array("oxNew", $args);
}
}
);
$this->assertSame(
$successfullySendExceptionMock,
$this->callMethod(
$sut,
'getSuccessSentMessage',
[$smsMock]
)
);
}
/**
* @return array
*/
public function canGetSuccessSentMessageDataProvider(): array
{
return [
'has response' => [true],
'has no response' => [false],
];
}
/**
* @test
* @param $hasResponse
* @return void
* @throws ReflectionException
* @covers \D3\Linkmobility4OXID\Application\Controller\Admin\AdminOrder::getUnsuccessfullySentMessage
* @dataProvider canGetSuccessSentMessageDataProvider
*/
public function canGetUnsuccessfullySentMessage($hasResponse)
{
/** @var Response|MockObject $resonseMock */
$resonseMock = $this->getMockBuilder(Response::class)
->onlyMethods(['getErrorMessage'])
->disableOriginalConstructor()
->getMock();
$resonseMock->expects($hasResponse ? $this->once() : $this->never())->method('getErrorMessage')
->willReturn('errorMessage');
/** @var Sms|MockObject $smsMock */
$smsMock = $this->getMockBuilder(Sms::class)
->disableOriginalConstructor()
->onlyMethods(['getResponse'])
->getMock();
$smsMock->method('getResponse')->willReturn($hasResponse ? $resonseMock : null);
/** @var AdminOrder|MockObject $sut */
$sut = $this->getMockBuilder(AdminOrder::class)
->disableOriginalConstructor()
->getMock();
$this->assertIsString(
$this->callMethod(
$sut,
'getUnsuccessfullySentMessage',
[$smsMock]
)
);
}
}