在 PhpUnit 中测试令牌过期的正确方法
Correct approach to test token expiration in PhpUnit
我已经编写了获取 JWT 令牌并将其缓存 59 分钟的服务。我现在正在为此服务编写测试。
在我的 AuthService 中,我有 2 种方法:
public function getToken(): string
{
$token = $this->cache->getItem('access_token');
// Czy jest token w cache
if ($token->isHit()) {
return $token->get();
} else {
$newToken = $this->getNewToken();
$this->saveTokenInCache($newToken);
return $newToken;
}
}
private function saveTokenInCache($tokenToSave): void
{
$savedToken = $this->cache->getItem('access_token');
$savedToken->set($tokenToSave);
$savedToken->expiresAfter(3540);
$this->cache->save($savedToken);
}
我有一个测试:
/**
* @test
*/
public function new_token_should_be_fetched_after_expiration()
{
$this->msGraphAuthService->expects($this->exactly(2))
->method('getNewToken');
// getToken
$this->msGraphAuthService->getToken();
// change time
$date = new DateTime();
$date->modify('3541 seconds');
$this->msGraphAuthService->getToken();
}
对于缓存,我正在使用 FileSystemAdapter
。
模拟 getNewToken
方法的设置函数是:
protected function setUp(): void
{
$kernel = self::bootKernel();
$this->cacheService = new FilesystemAdapter();
$this->serializer = $kernel->getContainer()->get('serializer');
$this->logger = $this->createMock(Logger::class);
$this->msGraphAuthService =$this>getMockBuilder(MicrosoftGraphAuthService::class)
->onlyMethods(['getNewToken'])
->setConstructorArgs([$this->logger, "", "", "", ""])
->getMock();
$this->msGraphAuthService
->method('getNewToken')
->willReturn('{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"eyJ..."}');
}
我在测试 new_token_should_be_fetched_after_expiration 中的确切目标是检查 getNewToken 方法是否被恰好调用了 2 次,但是怎么可能我把时间往前拨了59分钟?
我尝试做类似的事情:
$date = new DateTime();
$date->modify('3541 seconds');
但它不起作用。
我将不胜感激。
看起来时间是 getNewToken()
的隐藏依赖项。
使依赖关系更加明显。例如。是 $_SERVER['REQUEST_TIME']
还是更专用的 $date
默认参数(或您在实现中拥有的任何参数):
...
$date = new DateTime();
$token = $this->getNewToken($date);
...
然后您可以轻松创建即将过期的令牌,已经过期的令牌and/or您也可以删除时间对检查例程的隐藏依赖性。
幸运的是我找到了解决方案:
/**
* @test
*
*/
public function new_token_should_be_fetched_again_after_expiration()
{
ClockMock::register(CacheItem::class);
ClockMock::withClockMock(microtime(true) - 3600 * 24);
// should be invoked exactly 2 times
$this->msGraphAuthService->expects($this->exactly(2))
->method('getNewToken');
// getToken
$this->msGraphAuthService->getToken();
$this->msGraphAuthService->getToken();
}
行数:
ClockMock::register(CacheItem::class);
ClockMock::withClockMock(microtime(true) - 3600 * 24);
因为 CacheItem class 将从 ClockMock 调用假方法。在第二行中,我将当前时间设置为 24 小时前。它导致令牌立即过期。
我已经编写了获取 JWT 令牌并将其缓存 59 分钟的服务。我现在正在为此服务编写测试。 在我的 AuthService 中,我有 2 种方法:
public function getToken(): string
{
$token = $this->cache->getItem('access_token');
// Czy jest token w cache
if ($token->isHit()) {
return $token->get();
} else {
$newToken = $this->getNewToken();
$this->saveTokenInCache($newToken);
return $newToken;
}
}
private function saveTokenInCache($tokenToSave): void
{
$savedToken = $this->cache->getItem('access_token');
$savedToken->set($tokenToSave);
$savedToken->expiresAfter(3540);
$this->cache->save($savedToken);
}
我有一个测试:
/**
* @test
*/
public function new_token_should_be_fetched_after_expiration()
{
$this->msGraphAuthService->expects($this->exactly(2))
->method('getNewToken');
// getToken
$this->msGraphAuthService->getToken();
// change time
$date = new DateTime();
$date->modify('3541 seconds');
$this->msGraphAuthService->getToken();
}
对于缓存,我正在使用 FileSystemAdapter
。
模拟 getNewToken
方法的设置函数是:
protected function setUp(): void
{
$kernel = self::bootKernel();
$this->cacheService = new FilesystemAdapter();
$this->serializer = $kernel->getContainer()->get('serializer');
$this->logger = $this->createMock(Logger::class);
$this->msGraphAuthService =$this>getMockBuilder(MicrosoftGraphAuthService::class)
->onlyMethods(['getNewToken'])
->setConstructorArgs([$this->logger, "", "", "", ""])
->getMock();
$this->msGraphAuthService
->method('getNewToken')
->willReturn('{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"eyJ..."}');
}
我在测试 new_token_should_be_fetched_after_expiration 中的确切目标是检查 getNewToken 方法是否被恰好调用了 2 次,但是怎么可能我把时间往前拨了59分钟?
我尝试做类似的事情:
$date = new DateTime();
$date->modify('3541 seconds');
但它不起作用。
我将不胜感激。
看起来时间是 getNewToken()
的隐藏依赖项。
使依赖关系更加明显。例如。是 $_SERVER['REQUEST_TIME']
还是更专用的 $date
默认参数(或您在实现中拥有的任何参数):
...
$date = new DateTime();
$token = $this->getNewToken($date);
...
然后您可以轻松创建即将过期的令牌,已经过期的令牌and/or您也可以删除时间对检查例程的隐藏依赖性。
幸运的是我找到了解决方案:
/**
* @test
*
*/
public function new_token_should_be_fetched_again_after_expiration()
{
ClockMock::register(CacheItem::class);
ClockMock::withClockMock(microtime(true) - 3600 * 24);
// should be invoked exactly 2 times
$this->msGraphAuthService->expects($this->exactly(2))
->method('getNewToken');
// getToken
$this->msGraphAuthService->getToken();
$this->msGraphAuthService->getToken();
}
行数:
ClockMock::register(CacheItem::class);
ClockMock::withClockMock(microtime(true) - 3600 * 24);
因为 CacheItem class 将从 ClockMock 调用假方法。在第二行中,我将当前时间设置为 24 小时前。它导致令牌立即过期。