This commit is contained in:
Kris
2026-03-27 18:01:17 +08:00
parent 86c2d549e2
commit f439bfffe8
450 changed files with 63870 additions and 1408 deletions

View File

@@ -0,0 +1,727 @@
<?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, '分页循环下多语言同步条数应等于总条数');
}
}