Skip to content

Commit 5d227f9

Browse files
authored
增加單元測試 (#4)
* 增加 composer scripts * Added StubGeneratorCommandTest * 基本測試 * 分離成兩個測試情境 * 增加目錄生成單元測試 * 增加 getDestinationPath 測試 * 增加 putFile 測試 * 修正並完善 getDestinationPath 時的解析 * 修改 README.md
1 parent 70f7dde commit 5d227f9

16 files changed

+482
-60
lines changed

.github/animation.gif

251 KB
Loading

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
.env
44
.php_cs.cache
55
.phpunit.result.cache
6-
composer.lock
6+
composer.lock

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# A2Workspace/Laravel-Stubs
22

3+
<p align="center"><img src="/.github/animation.gif" alt="Laravel-Stubs demo"></p>
4+
35
一個基於專案的程式模板注入器。
46

57
透過在專案中的 `resources/stubs` 目錄下,放置類別的模板文件,然後透過命令快速注入並生成。相比原生的 `artisan make:*` 命令可大大減少編寫時間,且模板檔案可隨版控被 git 紀錄。
@@ -20,8 +22,8 @@ composer require "a2workspace/laravel-stubs:*"
2022

2123
## Usage | 如何使用
2224

23-
現在你可以使用 `make:a..` [Artisan 命令](https://laravel.com/docs/9.x/artisan)來生成類別。該命令將會讀取 `resources/stubs` 下的目錄或 `.php` 檔案,將佔位符依照格式替換為給定的名稱,並依照類別名稱自動生成檔案到相對的路徑。
25+
現在你可以使用 `make:a...` [Artisan 命令](https://laravel.com/docs/9.x/artisan)來生成類別。該命令將會讀取 `resources/stubs` 下的目錄或 `.php` 檔案,將佔位符依照格式替換為給定的名稱,並依照類別名稱自動生成檔案到相對的路徑。
2426

2527
```
26-
php artisan make:a..
28+
php artisan make:a...
2729
```

composer.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,19 @@
2424
"Tests\\": "tests/"
2525
}
2626
},
27-
"config": {
28-
"platform": {
29-
"ext-posix": "0"
30-
}
31-
},
3227
"extra": {
3328
"laravel": {
3429
"providers": [
3530
"A2Workspace\\Stubs\\ServiceProvider"
3631
]
3732
}
33+
},
34+
"scripts": {
35+
"test": [
36+
"vendor/bin/phpunit"
37+
],
38+
"test-coverage": [
39+
"vendor/bin/phpunit --coverage-html coverage"
40+
]
3841
}
3942
}

phpunit.xml.dist

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
stopOnFailure="false"
1414
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
1515
>
16+
<coverage>
17+
<include>
18+
<directory suffix=".php">src</directory>
19+
</include>
20+
</coverage>
1621
<testsuites>
17-
<testsuite name="Unit">
18-
<directory suffix="Test.php">./tests/Unit</directory>
19-
</testsuite>
20-
<testsuite name="Feature">
21-
<directory suffix="Test.php">./tests/Feature</directory>
22+
<testsuite name="Package Test">
23+
<directory suffix="Test.php">./tests/</directory>
2224
</testsuite>
2325
</testsuites>
2426
<php>

src/Commands/StubGeneratorCommand.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Symfony\Component\Finder\Finder;
1010
use Symfony\Component\Finder\SplFileInfo;
1111

12+
#[AsCommand(name: 'make:a...')]
1213
class StubGeneratorCommand extends Command
1314
{
1415
/**
@@ -45,7 +46,7 @@ class StubGeneratorCommand extends Command
4546
/**
4647
* @var string
4748
*/
48-
const REGEXP_NAMESPACE = '/^namespace (([A-Z][a-zA-Z]+)(\\\[A-Z][a-zA-Z]+)+);/m';
49+
const REGEXP_NAMESPACE = '/^namespace (([A-Z][a-zA-Z]+)(\\\[A-Z][a-zA-Z]+)*);/m';
4950

5051
/**
5152
* @var string
@@ -330,28 +331,39 @@ protected function getDestinationPath($built)
330331
}
331332

332333
// 接著,我們嘗試比對 namespace。若符合則生成對應目錄的完整路徑。
333-
// 目前支援 App\ 與 Tests\
334334
$destinations = [
335335
$this->laravel->getNamespace() => $this->laravel['path'],
336336
'Tests\\' => $this->laravel->basePath('tests'),
337-
'Database\\' => $this->laravel->basePath('database'),
337+
'Database\\Factories' => $this->laravel->databasePath('factories'),
338+
'Database\\Seeders' => $this->laravel->databasePath('seeders'),
338339
];
339340

340341
foreach ($destinations as $rootNamespace => $destination) {
341-
if (! Str::startsWith($namespace, $rootNamespace)) {
342+
// 處理 namespace Test\Feature; 這種情形
343+
if (Str::startsWith($namespace, $rootNamespace)) {
344+
$relative = Str::replaceFirst($rootNamespace, '', $namespace);
345+
$relative = str_replace('\\', '/', $relative);
346+
}
347+
// 處理 namespace Test; 這種情形
348+
else if ($namespace === substr($rootNamespace, 0, -1)) {
349+
$relative = '';
350+
}
351+
// 例外則跳過
352+
else {
342353
continue;
343354
}
344355

345-
$relative = Str::replaceFirst($rootNamespace, '', $namespace);
346-
$relative = str_replace('\\', '/', $relative);
347-
348-
$path = join('/', [
356+
$path = [
349357
$destination,
350358
$relative,
351359
"{$classname}.php"
352-
]);
360+
];
361+
362+
$path = join('/', $path);
363+
$path = str_replace('//', '/', $path);
364+
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
353365

354-
return str_replace('/', DIRECTORY_SEPARATOR, $path);
366+
return $path;
355367
}
356368

357369
return false;

tests/CallArtisanCommandTest.php

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
3+
namespace Tests;
4+
5+
use Illuminate\Testing\PendingCommand;
6+
use Tests\TestCase;
7+
8+
class CallArtisanCommandTest extends TestCase
9+
{
10+
protected function setUp(): void
11+
{
12+
parent::setUp();
13+
14+
@unlink(app_path(static::resolvePath('Models/Category.php')));
15+
@unlink(app_path(static::resolvePath('Http/Resources/CategoryResource.php')));
16+
}
17+
18+
protected function tearDown(): void
19+
{
20+
parent::tearDown();
21+
22+
@unlink(app_path(static::resolvePath('Models/Category.php')));
23+
@unlink(app_path(static::resolvePath('Http/Resources/CategoryResource.php')));
24+
}
25+
26+
private function expectsCommandChoice(PendingCommand $command, $answer): PendingCommand
27+
{
28+
$options = [
29+
'model.stub.php',
30+
static::resolvePath('pack/'),
31+
];
32+
33+
$command->expectsChoice(
34+
'選擇要使用的 Stub 檔案',
35+
$answer,
36+
$options,
37+
);
38+
39+
return $command;
40+
}
41+
42+
// =========================================================================
43+
// = Tests
44+
// =========================================================================
45+
46+
public function test_call_artisan_command()
47+
{
48+
$expectedPutPath = app_path(static::resolvePath('Models/Category.php'));
49+
50+
$command = $this->artisan('make:a...');
51+
$command = $this->expectsCommandChoice($command, 'model.stub.php');
52+
53+
$command->expectsQuestion('請輸入要注入的名稱', 'Category');
54+
55+
$command->expectsOutput(sprintf('已建立 "%s"', $expectedPutPath));
56+
$command->assertExitCode(0);
57+
$command->run();
58+
59+
$this->assertFileExists($expectedPutPath);
60+
$this->assertFileEquals(
61+
__DIR__ . '/fixtures/category_model.php',
62+
$expectedPutPath,
63+
);
64+
}
65+
66+
public function test_call_artisan_command_in_already_exists_and_overwrite()
67+
{
68+
$expectedPutPath = app_path(static::resolvePath('Models/Category.php'));
69+
70+
file_put_contents($expectedPutPath, '__EMPTY__');
71+
72+
$command = $this->artisan('make:a...');
73+
$command = $this->expectsCommandChoice($command, 'model.stub.php');
74+
75+
$command->expectsQuestion('請輸入要注入的名稱', 'Category');
76+
$command->expectsConfirmation(
77+
sprintf('%s 檔案已存在,是否要覆蓋?', $expectedPutPath),
78+
'yes'
79+
);
80+
81+
$command->expectsOutput(sprintf('已建立 "%s"', $expectedPutPath));
82+
$command->assertExitCode(0);
83+
$command->run();
84+
85+
$this->assertFileExists($expectedPutPath);
86+
$this->assertFileEquals(
87+
__DIR__ . '/fixtures/category_model.php',
88+
$expectedPutPath,
89+
);
90+
}
91+
92+
public function test_call_artisan_command_in_already_exists_and_without_overwrite()
93+
{
94+
$expectedPutPath = app_path(static::resolvePath('Models/Category.php'));
95+
96+
file_put_contents($expectedPutPath, '__EMPTY__');
97+
98+
$command = $this->artisan('make:a...');
99+
$command = $this->expectsCommandChoice($command, 'model.stub.php');
100+
101+
$command->expectsQuestion('請輸入要注入的名稱', 'Category');
102+
$command->expectsConfirmation(
103+
sprintf('%s 檔案已存在,是否要覆蓋?', $expectedPutPath),
104+
'no'
105+
);
106+
107+
$command->expectsOutput(
108+
sprintf('略過處理 %s', $expectedPutPath)
109+
);
110+
111+
$command->assertExitCode(0);
112+
$command->run();
113+
114+
$this->assertFileExists($expectedPutPath);
115+
$this->assertEquals(
116+
'__EMPTY__',
117+
file_get_contents($expectedPutPath),
118+
);
119+
}
120+
121+
public function test_call_artisan_command_with_filter()
122+
{
123+
$expectedPutPath = app_path(static::resolvePath('Models/Category.php'));
124+
125+
$command = $this->artisan('make:a...', [
126+
'filter' => 'model',
127+
]);
128+
129+
$command->expectsChoice(
130+
'選擇要使用的 Stub 檔案',
131+
'model.stub.php',
132+
['model.stub.php'],
133+
);
134+
135+
$command->expectsQuestion('請輸入要注入的名稱', 'Category');
136+
137+
$command->expectsOutput(sprintf('已建立 "%s"', $expectedPutPath));
138+
$command->assertExitCode(0);
139+
$command->run();
140+
141+
$this->assertFileExists($expectedPutPath);
142+
$this->assertFileEquals(
143+
__DIR__ . '/fixtures/category_model.php',
144+
$expectedPutPath,
145+
);
146+
}
147+
148+
public function test_call_artisan_command_with_filter_and_not_found()
149+
{
150+
$command = $this->artisan('make:a...', [
151+
'filter' => 'foobar',
152+
]);
153+
154+
$command->expectsOutput('找不到符合的 Stub 檔案');
155+
$command->assertExitCode(0);
156+
$command->run();
157+
}
158+
159+
public function test_call_artisan_command_with_directroy()
160+
{
161+
$expectedPutPath1 = app_path(static::resolvePath('Models/Category.php'));
162+
$expectedPutPath2 = app_path(static::resolvePath('Http/Resources/CategoryResource.php'));
163+
164+
$command = $this->artisan('make:a...');
165+
$command = $this->expectsCommandChoice(
166+
$command,
167+
static::resolvePath('pack/')
168+
);
169+
170+
$command->expectsQuestion('請輸入要注入的名稱', 'Category');
171+
172+
$command->expectsOutput(sprintf('已建立 "%s"', $expectedPutPath1));
173+
$command->expectsOutput(sprintf('已建立 "%s"', $expectedPutPath2));
174+
$command->assertExitCode(0);
175+
$command->run();
176+
177+
$this->assertFileExists($expectedPutPath1);
178+
$this->assertFileEquals(
179+
__DIR__ . '/fixtures/category_model.php',
180+
$expectedPutPath1,
181+
);
182+
183+
$this->assertFileExists($expectedPutPath2);
184+
$this->assertFileEquals(
185+
__DIR__ . '/fixtures/category_resource.php',
186+
$expectedPutPath2,
187+
);
188+
}
189+
}

tests/Feature/ExampleTest.php

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)