Files
ECShopX/tests/RepositoryLangInterceptorTest.php
2026-03-27 18:01:17 +08:00

728 lines
28 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use CompanysBundle\Services\RepositoryLangInterceptor;
/**
* 单元测试RepositoryLangInterceptor 分页与执行顺序T2 updateBy >1 页、T5 deleteBy >1 页)
* 计划:.tasks/plans/repository-lang-interceptor-batch-fix.md
*/
class RepositoryLangInterceptorTest extends TestCase
{
/**
* 生成模拟的 list 项(含 company_id、主键
*/
private function makeListItems(string $primaryKey, int $count, int $startId = 1): array
{
$list = [];
for ($i = 0; $i < $count; $i++) {
$list[] = [
'company_id' => 1,
$primaryKey => $startId + $i,
];
}
return $list;
}
/**
* T1: updateBy ≤1 页 — Mock lists 返回 total_count=NN≤pageSize、list 含 N 条;断言 updateLangData 被调用 N 次。
*/
public function testUpdateBySinglePageCallsUpdateLangDataNTimes(): void
{
$primaryKey = 'id';
$callLog = [];
$N = 10;
$singlePage = $this->makeListItems($primaryKey, $N, 1);
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'updateBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => $singlePage, 'total_count' => $N],
['list' => [], 'total_count' => $N]
);
$target->expects($this->once())
->method('updateBy')
->willReturnCallback(function () use (&$callLog) {
$callLog[] = 'targetUpdateBy';
});
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$data = ['name' => 'x'];
$interceptor->updateBy($filter, $data);
$updateLangDataCount = $this->countInLog($callLog, 'updateLangData');
$this->assertSame($N, $updateLangDataCount, 'updateLangData 应被调用 N 次≤1 页时 N 条)');
}
/**
* T2: updateBy 多页 — 第1页100条、第2页50条、第3页0条共150条。
* 断言updateLangData 被调用 150 次;先 target->updateBy 再 updateLangData。
*/
public function testUpdateByMultiplePagesCallsUpdateLangDataForAllRecordsAndTargetBeforeMultilang(): void
{
$primaryKey = 'id';
$callLog = [];
$page1 = $this->makeListItems($primaryKey, 100, 1);
$page2 = $this->makeListItems($primaryKey, 50, 101);
$page3 = [];
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'updateBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => $page1, 'total_count' => 150],
['list' => $page2, 'total_count' => 150],
['list' => $page3, 'total_count' => 150]
);
$target->expects($this->once())
->method('updateBy')
->willReturnCallback(function () use (&$callLog) {
$callLog[] = 'targetUpdateBy';
});
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$data = ['name' => 'x'];
$interceptor->updateBy($filter, $data);
$updateLangDataCount = $this->countInLog($callLog, 'updateLangData');
$firstTarget = $this->firstIndexInLog($callLog, 'targetUpdateBy');
$firstMultilang = $this->firstIndexInLog($callLog, 'updateLangData');
$this->assertSame(150, $updateLangDataCount, 'updateLangData 应被调用 150 次(多页总条数)');
$this->assertLessThan($firstMultilang, $firstTarget, '应先执行 target->updateBy 再执行 updateLangData');
}
/**
* T3: updateBy 参数 — Mock target->lists断言调用时第二个参数不是 array即未传入 data仅首参为 filter。
*/
public function testUpdateByListsCalledWithFilterOnlyNotData(): void
{
$primaryKey = 'id';
$callLog = [];
$singlePage = $this->makeListItems($primaryKey, 1, 1);
$listsCalls = [];
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'updateBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnCallback(function ($firstArg, $secondArg = null) use ($singlePage, &$listsCalls) {
$listsCalls[] = ['first' => $firstArg, 'second' => $secondArg];
if (count($listsCalls) === 1) {
return ['list' => $singlePage, 'total_count' => 1];
}
return ['list' => [], 'total_count' => 1];
});
$target->expects($this->once())
->method('updateBy')
->willReturn(true);
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$data = ['name' => 'x'];
$interceptor->updateBy($filter, $data);
$this->assertNotEmpty($listsCalls, 'lists 应被调用');
foreach ($listsCalls as $call) {
$this->assertSame($filter, $call['first'], 'lists 首参应为 filter');
$this->assertFalse(is_array($call['second']), 'lists 第二参数不应为 array即未传入 data');
}
}
/**
* T5: deleteBy 多页 — 分页共 200 条。
* 断言deleteLang 被调用 200 次;先 deleteLang 再 target->deleteBy。
*/
public function testDeleteByMultiplePagesCallsDeleteLangForAllRecordsAndMultilangBeforeTarget(): void
{
$primaryKey = 'id';
$callLog = [];
$page1 = $this->makeListItems($primaryKey, 100, 1);
$page2 = $this->makeListItems($primaryKey, 100, 101);
$page3 = [];
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'deleteBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => $page1, 'total_count' => 200],
['list' => $page2, 'total_count' => 200],
['list' => $page3, 'total_count' => 200]
);
$target->expects($this->once())
->method('deleteBy')
->willReturnCallback(function () use (&$callLog) {
$callLog[] = 'targetDeleteBy';
});
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$interceptor->deleteBy($filter);
$deleteLangCount = $this->countInLog($callLog, 'deleteLang');
$lastDeleteLang = $this->lastIndexInLog($callLog, 'deleteLang');
$deleteByIndex = $this->firstIndexInLog($callLog, 'targetDeleteBy');
$this->assertSame(200, $deleteLangCount, 'deleteLang 应被调用 200 次(多页总条数)');
$this->assertGreaterThan($lastDeleteLang, $deleteByIndex, '应先执行完所有 deleteLang 再执行 target->deleteBy');
}
/**
* T4: deleteBy ≤1 页 — Mock lists 返回 1 页;断言 deleteLang 被调用次数 = list 条数。
*/
public function testDeleteBySinglePageCallsDeleteLangEqualToListCount(): void
{
$primaryKey = 'id';
$callLog = [];
$listCount = 5;
$singlePage = $this->makeListItems($primaryKey, $listCount, 1);
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'deleteBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => $singlePage, 'total_count' => $listCount],
['list' => [], 'total_count' => $listCount]
);
$target->expects($this->once())
->method('deleteBy')
->willReturn(true);
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$interceptor->deleteBy($filter);
$deleteLangCount = $this->countInLog($callLog, 'deleteLang');
$this->assertSame($listCount, $deleteLangCount, 'deleteLang 被调用次数应等于 list 条数');
}
/**
* T6: delete 与 deleteBy 一致 — 调用 delete($filter)mock lists 多页;断言 deleteLang 调用次数 = 总条数,且先多语言再 target->delete。
*/
public function testDeleteMultiplePagesCallsDeleteLangForAllThenTargetDelete(): void
{
$primaryKey = 'id';
$callLog = [];
$page1 = $this->makeListItems($primaryKey, 80, 1);
$page2 = $this->makeListItems($primaryKey, 30, 81);
$page3 = [];
$totalRows = 110;
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'delete'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => $page1, 'total_count' => $totalRows],
['list' => $page2, 'total_count' => $totalRows],
['list' => $page3, 'total_count' => $totalRows]
);
$target->expects($this->once())
->method('delete')
->willReturnCallback(function () use (&$callLog) {
$callLog[] = 'targetDelete';
});
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$interceptor->delete($filter);
$deleteLangCount = $this->countInLog($callLog, 'deleteLang');
$lastDeleteLang = $this->lastIndexInLog($callLog, 'deleteLang');
$deleteIndex = $this->firstIndexInLog($callLog, 'targetDelete');
$this->assertSame($totalRows, $deleteLangCount, 'deleteLang 应被调用总条数次(与 deleteBy 一致)');
$this->assertGreaterThan($lastDeleteLang, $deleteIndex, '应先执行完所有 deleteLang 再执行 target->delete');
}
/**
* @param array $options 可选 'isDefaultLang' => bool (默认 true), 'langField' => array
*/
private function createCommonLangSpy(array &$callLog, array $options = []): object
{
$isDefaultLang = $options['isDefaultLang'] ?? true;
return new class($callLog, $isDefaultLang) {
private $callLog;
private $isDefaultLang;
public function __construct(array &$callLog, bool $isDefaultLang = true)
{
$this->callLog = &$callLog;
$this->isDefaultLang = $isDefaultLang;
}
public function getParamsLang($repository, $data)
{
return $data;
}
public function getLangData($data, array $fields)
{
return ['data' => $data, 'langBag' => []];
}
public function isDefaultLang(?string $lang = null): bool
{
return $this->isDefaultLang;
}
public function stripLangFieldsFromData(array $data, array $langField): array
{
$copy = $data;
foreach ($langField as $v) {
$key = explode('|', $v)[0] ?? '';
if ($key !== '') {
unset($copy[$key]);
}
}
return $copy;
}
public function saveLang(int $companyId, array $langBag, string $table, int $id, string $module, $langue = '')
{
$this->callLog[] = 'saveLang';
}
public function updateLangData(int $companyId, array $langBag, string $tableName, int $dataId, string $module, $langue = '')
{
$this->callLog[] = 'updateLangData';
}
public function deleteLang(int $companyId, string $tableName, int $dataId, string $module)
{
$this->callLog[] = 'deleteLang';
}
};
}
private function injectCommonLangService(RepositoryLangInterceptor $interceptor, object $service): void
{
$ref = new \ReflectionClass($interceptor);
$prop = $ref->getProperty('commonLangModService');
$prop->setAccessible(true);
$prop->setValue($interceptor, $service);
}
private function countInLog(array $callLog, string $tag): int
{
$n = 0;
foreach ($callLog as $entry) {
if ($entry === $tag) {
$n++;
}
}
return $n;
}
private function firstIndexInLog(array $callLog, string $tag): ?int
{
foreach ($callLog as $i => $entry) {
if ($entry === $tag) {
return $i;
}
}
return null;
}
private function lastIndexInLog(array $callLog, string $tag): ?int
{
$last = null;
foreach ($callLog as $i => $entry) {
if ($entry === $tag) {
$last = $i;
}
}
return $last;
}
/**
* processByFilterInPages仅用 filter 分页循环,每页 list 交给回调list 为空即停止。
* #given mock target->lists 第1页100条、第2页50条、第3页空
* #when 通过反射调用 processByFilterInPages($filter, $processPageList)
* #then 回调被调用 2 次,收到的 list 长度分别为 100、50lists 调用参数为 (filter,'*',page,500)
*/
public function testProcessByFilterInPagesIteratesUntilListEmptyAndCallsCallbackPerPage(): void
{
$primaryKey = 'id';
$page1 = $this->makeListItems($primaryKey, 100, 1);
$page2 = $this->makeListItems($primaryKey, 50, 101);
$page3 = [];
$listsCalls = [];
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnCallback(function ($filter, $cols, $page, $pageSize) use ($page1, $page2, $page3, &$listsCalls) {
$listsCalls[] = ['filter' => $filter, 'cols' => $cols, 'page' => $page, 'pageSize' => $pageSize];
if ($page === 1) {
return ['list' => $page1, 'total_count' => 150];
}
if ($page === 2) {
return ['list' => $page2, 'total_count' => 150];
}
return ['list' => $page3, 'total_count' => 150];
});
$interceptor = new RepositoryLangInterceptor($target);
$receivedLists = [];
$processPageList = function (array $list) use (&$receivedLists) {
$receivedLists[] = $list;
};
$filter = ['company_id' => 1];
$ref = new \ReflectionClass($interceptor);
$method = $ref->getMethod('processByFilterInPages');
$method->setAccessible(true);
$method->invoke($interceptor, $filter, $processPageList);
$this->assertCount(2, $receivedLists, '回调应被调用 2 次(两页有数据)');
$this->assertCount(100, $receivedLists[0], '第 1 页 list 长度 100');
$this->assertCount(50, $receivedLists[1], '第 2 页 list 长度 50');
$this->assertCount(3, $listsCalls, 'lists 应被调用 3 次(第 3 次返回空结束)');
$this->assertSame($filter, $listsCalls[0]['filter']);
$this->assertSame('*', $listsCalls[0]['cols']);
$this->assertSame(500, $listsCalls[0]['pageSize']);
$this->assertSame(1, $listsCalls[0]['page']);
$this->assertSame(2, $listsCalls[1]['page']);
$this->assertSame(3, $listsCalls[2]['page']);
}
/**
* TC1计划 default-lang-config默认语言 create 时target->create 收到原样 params含多语言字段
*/
public function testCreateWhenDefaultLangPassesParamsUnchangedToTarget(): void
{
$primaryKey = 'id';
$langField = ['content|json'];
$createReceived = null;
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['create'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = $langField;
$target->expects($this->once())
->method('create')
->willReturnCallback(function (...$args) use (&$createReceived, $primaryKey) {
$createReceived = $args;
return [$primaryKey => 1, 'company_id' => 1];
});
$callLog = [];
$spy = $this->createCommonLangSpy($callLog, ['isDefaultLang' => true]);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$data = ['name' => 'n1', 'content' => 'zh value'];
$interceptor->create($data);
$this->assertNotNull($createReceived);
$this->assertCount(1, $createReceived);
$passedData = $createReceived[0];
$this->assertArrayHasKey('content', $passedData, '默认语言时应原样传参,含多语言字段');
$this->assertSame('zh value', $passedData['content']);
}
/**
* TC2计划 default-lang-config非默认语言 create 时target->create 收到的是剔除多语言字段后的 data原始表不写多语言列。
*/
public function testCreateWhenNotDefaultLangPassesStrippedDataToTarget(): void
{
$primaryKey = 'id';
$langField = ['content|json'];
$createReceived = null;
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['create'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = $langField;
$target->expects($this->once())
->method('create')
->willReturnCallback(function (...$args) use (&$createReceived, $primaryKey) {
$createReceived = $args;
return [$primaryKey => 1, 'company_id' => 1];
});
$callLog = [];
$spy = $this->createCommonLangSpy($callLog, ['isDefaultLang' => false]);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$data = ['name' => 'n1', 'content' => 'lang value'];
$interceptor->create($data);
$this->assertNotNull($createReceived, 'target->create 应被调用');
$this->assertCount(1, $createReceived, 'create 单参数即 data');
$passedData = $createReceived[0];
$this->assertIsArray($passedData);
$this->assertArrayHasKey('name', $passedData);
$this->assertSame('n1', $passedData['name']);
$this->assertArrayNotHasKey('content', $passedData, '非默认语言时不应向原始表写入多语言字段 content');
}
/**
* TC2 updateOneBy非默认语言时 target->updateOneBy 收到 (filter, 剔除多语言字段后的 data)。
*/
public function testUpdateOneByWhenNotDefaultLangPassesStrippedDataToTarget(): void
{
$primaryKey = 'id';
$langField = ['content|json'];
$updateOneByReceived = null;
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['updateOneBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = $langField;
$target->expects($this->once())
->method('updateOneBy')
->willReturnCallback(function (...$args) use (&$updateOneByReceived, $primaryKey) {
$updateOneByReceived = $args;
return [$primaryKey => 1, 'company_id' => 1];
});
$callLog = [];
$spy = $this->createCommonLangSpy($callLog, ['isDefaultLang' => false]);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['id' => 1];
$data = ['name' => 'u1', 'content' => 'lang value'];
$interceptor->updateOneBy($filter, $data);
$this->assertNotNull($updateOneByReceived);
$this->assertCount(2, $updateOneByReceived, '约定 (filter, data)');
$this->assertSame($filter, $updateOneByReceived[0]);
$passedData = $updateOneByReceived[1];
$this->assertArrayHasKey('name', $passedData);
$this->assertSame('u1', $passedData['name']);
$this->assertArrayNotHasKey('content', $passedData, '非默认语言时不应向原始表写入多语言字段');
}
/**
* TC5计划 default-lang-config非默认语言 updateBy 时target->updateBy 收到 (filter, 剔除多语言字段后的 data)。
*/
public function testUpdateByWhenNotDefaultLangPassesStrippedDataToTarget(): void
{
$primaryKey = 'id';
$langField = ['content|json'];
$updateByReceived = null;
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['updateBy', 'lists'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = $langField;
$target->expects($this->once())
->method('updateBy')
->willReturnCallback(function ($filter, ...$args) use (&$updateByReceived) {
$updateByReceived = [$filter, $args];
return 1;
});
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => [], 'total_count' => 0]
);
$callLog = [];
$spy = $this->createCommonLangSpy($callLog, ['isDefaultLang' => false]);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$data = ['name' => 'u1', 'content' => 'lang value'];
$interceptor->updateBy($filter, $data);
$this->assertNotNull($updateByReceived);
$this->assertCount(2, $updateByReceived);
$this->assertSame($filter, $updateByReceived[0]);
$params = $updateByReceived[1];
$this->assertCount(1, $params, '约定 params[0] 为 data');
$passedData = $params[0];
$this->assertArrayHasKey('name', $passedData);
$this->assertSame('u1', $passedData['name']);
$this->assertArrayNotHasKey('content', $passedData, '非默认语言时不应向原始表写入多语言字段');
}
/**
* TC7 updateOneBy调用方传入的 data 在 updateOneBy 后未被篡改。
*/
public function testUpdateOneByWhenNotDefaultLangDoesNotMutateCallerData(): void
{
$primaryKey = 'id';
$langField = ['content|json'];
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['updateOneBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = $langField;
$target->expects($this->once())->method('updateOneBy')->willReturn([$primaryKey => 1, 'company_id' => 1]);
$callLog = [];
$spy = $this->createCommonLangSpy($callLog, ['isDefaultLang' => false]);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['id' => 1];
$data = ['name' => 'u1', 'content' => 'lang value'];
$interceptor->updateOneBy($filter, $data);
$this->assertArrayHasKey('content', $data);
$this->assertSame('lang value', $data['content'], '调用方 data 的 content 未被篡改');
}
/**
* TC7计划 default-lang-config调用方传入的 data 在 create 后未被篡改Interceptor 只对副本剔除。
*/
public function testCreateWhenNotDefaultLangDoesNotMutateCallerData(): void
{
$primaryKey = 'id';
$langField = ['content|json'];
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['create'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = $langField;
$target->expects($this->once())->method('create')->willReturn([$primaryKey => 1, 'company_id' => 1]);
$callLog = [];
$spy = $this->createCommonLangSpy($callLog, ['isDefaultLang' => false]);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$data = ['name' => 'n1', 'content' => 'lang value'];
$interceptor->create($data);
$this->assertArrayHasKey('content', $data, '调用方 data 应仍含 content');
$this->assertSame('lang value', $data['content'], '调用方 data 的 content 未被篡改');
}
/**
* T7: 分页循环一致性 — 仅用分页循环时,多页 mock 下断言多语言同步条数正确。
*/
public function testPaginationLoopSyncCountConsistency(): void
{
$primaryKey = 'id';
$callLog = [];
$page1 = $this->makeListItems($primaryKey, 40, 1);
$page2 = $this->makeListItems($primaryKey, 30, 41);
$page3 = $this->makeListItems($primaryKey, 20, 71);
$page4 = [];
$totalRows = 90;
$target = $this->getMockBuilder(\stdClass::class)
->addMethods(['lists', 'deleteBy'])
->getMock();
$target->table = 'test_table';
$target->module = 'test_module';
$target->primaryKey = $primaryKey;
$target->langField = [];
$target->expects($this->atLeastOnce())
->method('lists')
->willReturnOnConsecutiveCalls(
['list' => $page1, 'total_count' => $totalRows],
['list' => $page2, 'total_count' => $totalRows],
['list' => $page3, 'total_count' => $totalRows],
['list' => $page4, 'total_count' => $totalRows]
);
$target->expects($this->once())
->method('deleteBy')
->willReturn(true);
$spy = $this->createCommonLangSpy($callLog);
$interceptor = new RepositoryLangInterceptor($target);
$this->injectCommonLangService($interceptor, $spy);
$filter = ['company_id' => 1];
$interceptor->deleteBy($filter);
$deleteLangCount = $this->countInLog($callLog, 'deleteLang');
$this->assertSame($totalRows, $deleteLangCount, '分页循环下多语言同步条数应等于总条数');
}
}