createHandler()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 10
ccs 7
cts 7
cp 1
crap 1
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
4
namespace Stockbase\Integration\Test\Unit\Model\Observer;
5
6
use Magento\CatalogInventory\Api\StockRegistryInterface;
7
use Magento\CatalogInventory\Observer\ItemsForReindex;
8
use Magento\CatalogInventory\Observer\ProductQty;
9
use Magento\CatalogInventory\Api\StockManagementInterface;
10
use Magento\Framework\Event\Observer as EventObserver;
11
use Magento\Framework\TestFramework\Unit\Matcher\MethodInvokedAtIndex;
12
use PHPUnit\Framework\TestCase;
13
use Stockbase\Integration\Model\Inventory\StockbaseStockManagement;
14
use Stockbase\Integration\Model\Observer\SubtractQuoteInventoryObserver;
15
use Stockbase\Integration\Model\StockItemReserve;
16
17
/**
18
 * Class SubtractQuoteInventoryObserverTest
19
 */
20
class SubtractQuoteInventoryObserverTest extends TestCase
21
{
22
    const TEST_WEBSITE_ID = 0xdeadbeef;
23
    
24
    /** @var StockManagementInterface|\PHPUnit_Framework_MockObject_MockObject */
25
    private $stockManagement;
26
27
    /** @var ProductQty|\PHPUnit_Framework_MockObject_MockObject */
28
    private $productQty;
29
30
    /** @var ItemsForReindex|\PHPUnit_Framework_MockObject_MockObject */
31
    private $itemsForReindex;
32
33
    /** @var StockRegistryInterface|\PHPUnit_Framework_MockObject_MockObject */
34
    private $stockRegistry;
35
36
    /** @var StockbaseStockManagement|\PHPUnit_Framework_MockObject_MockObject */
37
    private $stockbaseStockManagement;
38
39
    /** @var EventObserver */
40
    private $observer;
41
42
    /** @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject */
43
    private $quote;
44
45
    /** @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject */
46
    private $order;
47
48
    /**
49
     * {@inheritdoc}
50
     */
51 4
    public function setUp()
52
    {
53 4
        $this->stockManagement = $this->createMock(\Magento\CatalogInventory\Model\StockManagement::class);
54 4
        $this->productQty = $this->createMock(ProductQty::class);
55 4
        $this->itemsForReindex = $this->createMock(ItemsForReindex::class);
56 4
        $this->stockRegistry = $this->createMock(StockRegistryInterface::class);
57 4
        $this->stockbaseStockManagement = $this->createMock(StockbaseStockManagement::class);
58
59 4
        $this->quote = $this->getMockBuilder(\Magento\Quote\Model\Quote::class)
60 4
            ->disableOriginalConstructor()
61 4
            ->setMethods([
62 4
                'getInventoryProcessed',
63
                'setInventoryProcessed',
64
                'getAllItems',
65
                'getStore',
66
            ])
67 4
            ->getMock();
68
        
69 4
        $this->order = $this->getMockBuilder(\Magento\Sales\Model\Order::class)
70 4
            ->disableOriginalConstructor()
71 4
            ->setMethods(['addStatusHistoryComment'])
72 4
            ->getMock();
73
        
74 4
        $store = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class);
75 4
        $store->method('getWebsiteId')->willReturn(self::TEST_WEBSITE_ID);
76
        
77 4
        $this->quote->method('getStore')->willReturn($store);
78
        
79
        
80 4
        $this->observer = new \Magento\Framework\Event\Observer([
81 4
            'event' => new \Magento\Framework\Event([
82 4
                'quote' => $this->quote,
83 4
                'order' => $this->order,
84
            ]),
85
        ]);
86 4
    }
87
88
    /**
89
     * testInventoryProcessed
90
     */
91 1
    public function testInventoryProcessed()
92
    {
93 1
        $this->quote->method('getInventoryProcessed')->willReturn(true);
94
        
95 1
        $this->quote->expects($this->never())->method('setInventoryProcessed');
96
        
97 1
        $handler = $this->createHandler();
98 1
        $this->assertEquals($handler, $handler->execute($this->observer));
99 1
    }
100
101
    /**
102
     * testEmptyItems
103
     */
104 1
    public function testEmptyItems()
105
    {
106 1
        $this->quote->method('getInventoryProcessed')->willReturn(false);
107 1
        $this->quote->method('getAllItems')->willReturn([]);
108
109 1
        $this->stockManagement->expects($this->once())
110 1
            ->method('registerProductsSale')
111 1
            ->with([], self::TEST_WEBSITE_ID)
112 1
            ->willReturn([]);
113
114 1
        $this->itemsForReindex->expects($this->once())->method('setItems')->with([]);
115 1
        $this->quote->expects($this->once())->method('setInventoryProcessed')->with(true);
116
        
117 1
        $handler = $this->createHandler();
118 1
        $this->assertEquals($handler, $handler->execute($this->observer));
119 1
    }
120
121
    /**
122
     * testItems
123
     * @dataProvider itemsProvider
124
     */
125 2
    public function testItems()
126
    {
127 2
        $itemPrototypes = func_get_args();
128
129 2
        $items = [];
130 2
        $magentoReserve = [];
131 2
        $stockbaseAmounts = [];
132 2
        foreach ($itemPrototypes as $index => $itemPrototype) {
133 2
            $item = $this->getMockBuilder(\Magento\Quote\Model\Quote\Item::class)
134 2
                ->disableOriginalConstructor()
135 2
                ->setMethods(['getProductId', 'getChildrenItems', 'getTotalQty'])
136 2
                ->getMock();
137
138 2
            $item->method('getProductId')->willReturn($itemPrototype['productId']);
139 2
            $item->method('getChildrenItems')->willReturn([]);
140 2
            $item->method('getTotalQty')->willReturn($itemPrototype['requestedQty']);
141
142 2
            $items[$index] = $item;
143 2
            $magentoReserve[$itemPrototype['productId']] = $itemPrototype['magentoReserve'];
144 2
            $stockbaseAmounts[$itemPrototype['productId']] = $itemPrototype['stockbaseQty'];
145
146 2
            $stockItem = $this->createMock(\Magento\CatalogInventory\Api\Data\StockItemInterface::class);
147 2
            $stockItem->method('getQty')->willReturn($itemPrototype['magentoQty']);
148
            
149 2
            $this->stockRegistry->expects(new MethodInvokedAtIndex($index))->method('getStockItem')
150 2
                ->with($itemPrototype['productId'])
151 2
                ->willReturn($stockItem);
152
            
153 2
            if (!empty($itemPrototype['qtyException'])) {
154 1
                $this->expectException(\Magento\Framework\Exception\LocalizedException::class);
155 1
                $this->expectExceptionMessageRegExp('/Not all of your products are available in the requested quantity\./');
156
            } else {
157 1
                $reserveItem = $this->createMock(StockItemReserve::class);
158 1
                $reserveItem->method('getEan')->willReturn($itemPrototype['productId']);
159 1
                $reserveItem->method('getAmount')->willReturn($itemPrototype['stockbaseReserve']);
160
161 1
                $this->stockbaseStockManagement->expects(new MethodInvokedAtIndex($index))->method('createReserve')
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Stockbase\Integration\Mo...tockbaseStockManagement.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
162 1
                    ->with($item, $itemPrototype['stockbaseReserve'], $itemPrototype['magentoReserve'])
163 2
                    ->willReturn($reserveItem);
164
            }
165
        }
166
        
167
        
168 2
        $this->stockbaseStockManagement->method('isStockbaseProduct')->willReturn(true);
169
170 2
        $this->stockbaseStockManagement->method('getStockbaseStockAmount')
171 2
            ->willReturnCallback(function ($productId) use ($stockbaseAmounts) {
172 2
                return $stockbaseAmounts[$productId];
173 2
            });
174
        
175 2
        $this->quote->method('getInventoryProcessed')->willReturn(false);
176 2
        $this->quote->method('getAllItems')->willReturn($items);
177
178 2
        if (!$this->getExpectedException()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getExpectedException() of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
179 1
            $this->stockManagement->expects($this->once())
180 1
                ->method('registerProductsSale')
181 1
                ->with($magentoReserve, self::TEST_WEBSITE_ID)
182 1
                ->willReturn([]);
183
            
184 1
            $this->itemsForReindex->expects($this->once())->method('setItems')->with([]);
185
186 1
            $this->quote->expects($this->once())->method('setInventoryProcessed')->with(true);
187
        }
188
189 2
        $handler = $this->createHandler();
190 2
        $this->assertEquals($handler, $handler->execute($this->observer));
191 1
    }
192
193
    /**
194
     * itemsProvider
195
     * @return array
196
     */
197
    public function itemsProvider()
198
    {
199
        return [
200
            [
201
                [
202
                    'productId' => 101,
203
                    'magentoQty' => 3,
204
                    'stockbaseQty' => 2,
205
                    'requestedQty' => 5,
206
                    'magentoReserve' => 3,
207
                    'stockbaseReserve' => 2,
208
                ],
209
                [
210
                    'productId' => 102,
211
                    'magentoQty' => 0,
212
                    'stockbaseQty' => 5,
213
                    'requestedQty' => 3,
214
                    'magentoReserve' => 0,
215
                    'stockbaseReserve' => 3,
216
                ],
217
            ],
218
            [
219
                [
220
                    'productId' => 101,
221
                    'magentoQty' => 3,
222
                    'stockbaseQty' => 2,
223
                    'requestedQty' => 6,
224
                    'magentoReserve' => 0,
225
                    'stockbaseReserve' => 0,
226
                    'qtyException' => true,
227
                ],
228
            ],
229
        ];
230
    }
231
232 4
    protected function createHandler()
233
    {
234 4
        return new SubtractQuoteInventoryObserver(
235 4
            $this->stockManagement,
236 4
            $this->productQty,
237 4
            $this->itemsForReindex,
238 4
            $this->stockRegistry,
239 4
            $this->stockbaseStockManagement
240
        );
241
    }
242
}
243