Как выполнить модульное тестирование всех путей выполнения кода функциональности Laravel's Cache :: запомнить? - PullRequest
0 голосов
/ 17 апреля 2019

Я большой поклонник функциональности Laravel Cache::remember, и я использую ее в своих классах обслуживания следующим образом:

/**
 * SummaryService
 */
public function getSummaryData(string $userId)
{
    $summaryCacheKey = $userId . '_summary_cache';
    $summaryCacheLifespanMinutes = config('summary_cache_lifespan_minutes');

    return Cache::remember($summaryCacheKey, $summaryCacheLifespanMinutes, function () use ($userId) {

        $summaryResult = [
            'userExists' => false,
            'data' => [],
        ];

        $user = $this->userRepository->findById($userId);

        if ($user) {

            $summaryResult = [
                'userExists' => true,
                'data' => $this->summaryRepository->getSummaryByUserId($user->id),
            ];

        }

        return $summaryResult;

    });
}

Это работает как ожидалось. Если данные присутствуют в кэше, они возвращаются, а если нет, загружаются, кэшируются и возвращаются.

Теперь я пытаюсь выполнить модульное тестирование моего SummaryService (оба пути выполнения).

Первая часть, где данные возвращаются через кеш, легко тестируется и выглядит следующим образом:

public function i_can_load_summary_data_via_cache()
{
    // given
    $userId = 'aaaa45-bbbb-cccc-ddddssswwwdw';

    $expectedResult = [
        'userExists' => true,
        'data' => [ ... ],
    ];

    $summaryCacheKey = $userId . '_summary_cache';
    $summaryCacheLifespanMinutes = config('summary_cache_lifespan_minutes');

    Cache::shouldReceive('remember')
        ->once()
        ->with($summaryCacheKey, $summaryCacheLifespanMinutes, Closure::class)
        ->andReturn($expectedResult);

    // when
    $result = $this->summaryService->getSummaryData($userId);

    // then
    $this->assertSame($expectedResult, $result);
}

Однако, когда я пытаюсь протестировать сценарий, в котором данные отсутствуют в кеше, и я должен загрузить их (через смоделированные репозитории) примерно так:

public function i_can_load_summary_data_via_database()
{
    // given
    $userId = 'aaaa45-bbbb-cccc-ddddssswwwdw';

    $expectedResult = [
        'userExists' => true,
        'data' => [ ... ],
    ];

    $user = new User();
    $user->id = $userId;

    $summaryCacheKey = $userId . '_summary_cache';
    $summaryCacheLifespanMinutes = 0;

    Cache::shouldReceive('remember')
        ->once()
        ->with($summaryCacheKey, $summaryCacheLifespanMinutes, \Mockery::on(function() use($user) {
            $this->mockedUserRepository
                ->shouldReceive('findById')
                ->once()
                ->andReturn($user);
            $this->mockedSummaryRepository
                ->shouldReceive('getSummaryByUserId')
                ->once()
                ->with($user->id)
                ->andReturn([ ... ]);
        }))
        ->andReturn($expectedResult);

    // when
    $result = $this->summaryService->getSummaryData($userId);

    // then
    $this->assertSame($expectedResult, $result);
}

Тест не пройден:

Не найдено подходящего обработчика для Mockery_3_Illuminate_Cache_CacheManager :: запомнить ('aaaa45-bbbb-cccc-ddddssswwwdw_summary_cache', '10', объект (закрытие)). Либо метод был неожиданным, либо его для этого метода не найдено ни одного ожидаемого списка аргументов

Объекты: (массив ('Закрытие' => массив ( 'class' => 'Закрытие', 'свойства' => массив ( ),),))

Есть идеи, как правильно это проверить?

1 Ответ

0 голосов
/ 17 апреля 2019

Хорошо, я, кажется, слишком усложнил это;поэтому я разбил его и исправил немного по-другому, как это.

Мой сервисный код теперь выглядит так:

/**
 * SummaryService
 */

public function getSummaryData(string $userId)
{
    $summaryCacheKey = $userId . '_summary_cache';
    $summaryCacheLifespanMinutes = config('summary_cache_lifespan_minutes');

    return Cache::remember($summaryCacheKey, $summaryCacheLifespanMinutes, function () use ($userId) {
        return $this->loadLiveSummaryData($userId);
    });
}

public function loadLiveSummaryData(string $userId)
{
    $summaryResult = [
        'userExists' => false,
        'data' => [],
    ];

    $user = $this->userRepository->findById($userId);

    if ($user) {

        $summaryResult = [
            'userExists' => true,
            'data' => $this->summaryRepository->getSummaryByUserId($user->id),
        ];

    }

    return $summaryResult;
}

и теперь мне просто нужно подтвердить через мой модульный тест, что:

  1. Мой сервис может загружать кэшированную версию и сопоставлять параметры вызова
  2. , и я могу загружать данные в реальном времени (где я могу высмеивать репо)

Что выглядит примерно так:

/**
 * @test
 */
public function i_can_load_live_summary_data_for_existing_user()
{
    // given
    $userId = 'aaaa45-bbbb-cccc-ddddssswwwdw';

    $expectedResult = [
        'userExists' => true,
        'data' => [ ... ],
    ];

    $user = new User();
    $user->id = $userId;

    $this->mockedUserRepository
        ->shouldReceive('findById')
        ->once()
        ->andReturn($user);

    $this->mockedSummaryRepository
        ->shouldReceive('getSummaryByUserId')
        ->once()
        ->with($user->id)
        ->andReturn([ ... ]);

    // when
    $result = $this->summaryService->loadLiveSummaryData($userId);

    // then
    $this->assertSame($expectedResult, $result);
}

/**
 * @test
 */
public function i_expect_cache_to_be_called_when_loading_summary_data_for_specific_user()
{
    // given
    $userId = 'aaaa45-bbbb-cccc-ddddssswwwdw';

    $expectedResult = [
        'userExists' => true,
        'data' => [ ... ],
    ];

    $summaryCacheKey = $userId . '_summary_cache';
    $summaryCacheLifespanMinutes = 10;

    Cache::shouldReceive('remember')
        ->once()
        ->with($summaryCacheKey, $summaryCacheLifespanMinutes, \Mockery::on(function($value) {
            return is_callable($value);
        }))
        ->andReturn($expectedResult);

    // when
    $result = $this->summaryService->getSummaryData($userId);

    // then
    $this->assertSame($expectedResult, $result);
}

Дайте мне знать, если есть лучший или "правильный" способ сделать это.

...