createMock(UpstreamReadOnlyQuery::class); $query->expects($this->once())->method('select')->willReturnCallback( function (string $sql, array $bindings): array { UpstreamReadOnlyQuery::assertReadOnlySql($sql); $this->assertStringContainsString('[dbo].[aaronprice]', $sql); $this->assertStringContainsString('[条形码] LIKE ?', $sql); $this->assertStringContainsString('OFFSET 2 ROWS FETCH NEXT 3 ROWS ONLY', $sql); $this->assertSame( ['%ABC\\%\\_%', '定价', '是', '2026-07-01', '2026-07-31'], $bindings, ); return [ ['barcode' => 'A', 'price_before' => '10.00', 'price_after' => '11.50', 'price_diff' => '1.50'], ['barcode' => 'B', 'price_before' => '', 'price_after' => null, 'price_diff' => '0.00'], ['barcode' => 'C', 'price_before' => '3.00', 'price_after' => '4.00', 'price_diff' => '1.00'], ]; }, ); $factory = $this->createMock(UpstreamReadOnlyQueryFactory::class); $factory->expects($this->once())->method('forSource')->with('jiansun')->willReturn($query); $result = (new ProductPriceRepository($factory))->paginate([ 'barcode' => 'ABC%_', 'price_type' => 'pricing', 'cost_reduction' => 'yes', 'effective_from' => '2026-07-01', 'effective_to' => '2026-07-31', ], 2, 2); $this->assertCount(3, $result['rows']); $this->assertSame(10.0, $result['rows'][0]['price_before']); $this->assertSame(11.5, $result['rows'][0]['price_after']); $this->assertNull($result['rows'][1]['price_before']); $this->assertSame(0.0, $result['rows'][1]['price_diff']); } }