Laavel 테스트~복원 편으로
이 보도에 관하여
Laravel #2 Advent Calendar 2018 - Qiita 24일째 보도다.
팩스 편이긴 하지만 팩스가 거의 없고'휴대폰으로 의존관계를 교환한다'는 내용이니 크리스마스이브니까 용서해 주세요.
개시하다
개요
이 글은 단원 테스트라고 하지만 단원 테스트가 없는 곳이 있기 때문에 단원 테스트로 변경해야 한다.
Laavel 테스트~단원 테스트 편 - Qita
컨디션
이루어지다
구조기로 받아들일 의존 대상 변경
만일을 대비해서 먼저 원래의 코드를 놓아라.
<?php
namespace App\Models\Services\Calculators;
use App\Models\PeriodOfUse;
use App\Models\Specifications\DiscountSpecification;
class DiscountCalculator
{
public function run(PeriodOfUse $period, int $baseCharge): int
{
$specification = new DiscountSpecification();
if (!$specification->satisfied($period)) {
return 0;
}
return (int)floor($baseCharge / 10);
}
}
new DiscountSpecification 대신 로컬 변수를 대입하고 인스턴스를 구조기로 받아 속성에 들어갑니다.<?php
namespace App\Models\Services\Calculators;
use App\Models\PeriodOfUse;
use App\Models\Specifications\DiscountSpecification;
class DiscountCalculator
{
private $specification;
public function __construct(DiscountSpecification $specification)
{
$this->specification = $specification;
}
public function run(PeriodOfUse $period, int $baseCharge): int
{
if (!$this->specification->satisfied($period)) {
return 0;
}
return (int)floor($baseCharge / 10);
}
}
Specification은interface를 사용할 수 있지만 이번에는 구체적인 반이 하나밖에 없어서 그냥 놔뒀다.대상을 모듈화하는 몇 가지 방법
다음은
DiscountCalculatorTest::testRun()
의 수정이다.$specification
생성된 곳은 다음과 같다.// Mockery
$specification = Mockery::mock(Context::class)
->shouldReceive('satisfied')
->once()
->andReturn($satisfied)
->getMock();
// or
// PHPUnit MockObject
$specification = $this->createConfiguredMock(
Context::class,
['satisfied' => $satisfied]
);
$calculator = new DiscountCalculator($specification);
$discount = $calculator->run($period, $baseCharge);
Laavel에 Mockery가 미리 설치되어 있음Mockery::mock()
도 가능하며 PHPUnit에 내장된 모듈 클래스$this->createMock()
와 $this->createConfiguredMock()
도 사용할 수 있습니다.또한 Mockery와 MockObject 대신 PHP7에서 가져온 무명 클래스를 사용할 수도 있습니다.
$specification = new class extends DiscountSpecification {
public $satisfied;
public function satisfied(): bool {
return $this->satisfied;
}
};
$specification->satisfied = $satisfied;
모처럼 묶여서 모커리도 괜찮을 것 같은데 무명반을 쓴 걸 알았더라면 손해 볼 일은 없었을 텐데.satisfied의 행동은 단지 두 가지(진짜인지 가짜인지)일 뿐이기 때문에 DataProvider로부터 테스트 모델로 당신에게 맡깁니다.
- public function testRun(int $baseCharge, int $days, int $expected)
+ public function testRun(int $baseCharge, bool $satisfied, int $expected)
일수는 더 이상 DiscountCalculator
에 의존하지 않으니 적당히 넣으세요.이렇게 되면 Discount Calculator만 테스트할 수 있어 매우 좋은 단원 테스트입니다.
잡담
DI 컨테이너를 사용하는 경우도 다음과 같다.
DiscountCalculatorTest.php
$specification = Mockery::mock(DiscountSpecification::class)
->shouldReceive('satisfied')
->once()
->andReturn($satisfied)
->getMock();
$this->app->bind(DiscountSpecification::class, function () use ($specification) {
return $specification;
});
$this->app->bind('calculator', DiscountCalculator::class);
$calculator = app('calculator');
$discount = $calculator->run($period, $baseCharge);
$this->assertSame($expected, $discount);
제품 코드에 DI 용기가 사용되지 않더라도 테스트 시 테스트 대상과 모델 대상은 모두 용기를 이용해 초기화하면 의존 대상(위의 예에서 DiscountSpecification)도 자동으로 모듈로 교체돼 편리하다.최종 테스트 코드
일수가 의존에서 삭제되었기 때문에 테스트 모드에서도 제외됩니다.
DiscountCalculatorTest.php
<?php
namespace Tests\Unit;
use App\Models\PeriodOfUse;
use App\Models\Services\Calculators\DiscountCalculator;
use App\Models\Specifications\DiscountSpecification;
use App\Models\Specifications\Specification;
use Carbon\Carbon;
use Tests\TestCase;
use Mockery;
class DiscountCalculatorTest extends TestCase
{
/**
* @param int $baseCharge
* @param bool $satisfied
* @param int $expected
* @dataProvider dataRun
*/
public function testRun(int $baseCharge, bool $satisfied, int $expected)
{
$period = new PeriodOfUse(Carbon::today(), Carbon::today()->addDays(1));
$specification = Mockery::mock(DiscountSpecification::class)
->shouldReceive('satisfied')
->once()
->andReturn($satisfied)
->getMock();
$calculator = new DiscountCalculator($specification);
$discount = $calculator->run($period, $baseCharge);
$this->assertSame($expected, $discount);
}
public function dataRun()
{
return [
'値引きあり,端数なし' => [
'baseCharge' => 5000,
'satisfied' => true,
'expected' => 500,
],
'値引きあり,端数あり' => [
'baseCharge' => 4999,
'satisfied' => true,
'expected' => 499,
],
'値引きなし' => [
'baseCharge' => 5000,
'satisfied' => false,
'expected' => 0,
],
];
}
}
끝말
각양각색의 모듈화 방법이 있지만 기본적으로 모커리 사용을 추천하고 상황에 따라 무명반을 사용하는 것이 편할 수 있다(그렇게 말하지만 잠시 생각이 나지 않으니 아이디어가 있는 사람이 평론을 해주면 좋겠다.
Happy testing!
내일이 마지막 날, @jiyuujin의 "LARAVEL을 사용하여 \12294, 검증 및 페이지 관리"기대해주세요!
Reference
이 문제에 관하여(Laavel 테스트~복원 편으로), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/nunulk/items/73fac1a24af9cc265fc5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)