1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel】PHPSpreadSheetを使ってExcelファイルを作り、アップロードテストする

Last updated at Posted at 2023-04-24

久々の投稿です。よろしくお願いします。

課題

  • 元々Excelファイルをアップロードする処理はあったが、テストが無かった
  • テストデータは手作成でExcelを作ってアップロードし、目視で確認していたため効率が悪かった。

TL;DR

  • テストデータ作成用Factoryクラスを作る(LaravelのデータベースFactoryとは別)
  • テストデータはFactoryクラスで作成
  • テストデータのアップロードはUploadedFileクラスを使う

xlsxファイルFactoryクラスの作成

今回は「XlsxFileFactory」とでもしましょうか。

class XlsxFileFactory
{
    public array $importFileHeaders;
    public SpreadSheet $workBook;

    public function __construct(array $headers)
    {
        $this->workBook = new SpreadSheet();
        $this->importFileHeaders = $headers;
    }

    public function createDummyFile(int $createCount): void
    {
        $this->write($createCount);
        $writer = new Xlsx($this->workBook);
        $writer->save(base_path('storage/app/public/') . 'test.xlsx');
    }

    private function write(int $createCount): void
    {
        $workSheet = $this->workBook->getActiveSheet();
        $faker = Factory::create('ja_JP');

        // ヘッダの書き込み(ヘッダは配列をそのまま出力)
        $workSheet->fromArray($this->importFileHeaders, 'エラー', 'A1');

        // データ部の書き込み(データ部は書式を設定したりするのでループで処理)
        for ($i = 2; $i < $createCount+2; $i++) {
            // 数値5文字を標準書式で作成
            $workSheet->setCellValue('A'.$i, $faker->numerify('######'));

            // 日付を書式設定して入力
            $workSheet->getStyle('B'.$i)->getNumberFormat()->setFormatCode('yyyy/m/d h:mm');
            $workSheet->setCellValue('B'.$i, Date::PHPToExcel($faker->dateTime())); // DateTime型を渡すと書式設定通りに値が入る

            // 数値を文字として入力
            $workSheet->setCellValueExplicit('C'.$i, $faker->numberBetWeen(1,10), DataType::TYPE_STRING);
        }
    }
}

テストコードの作成

class ExampleTest extends TestCase
{
    public function setUp(): void
    {
        // ケースごとにセットアップしたいものをここに書く
        // hogehoge...

        parent::__construct();
    }

    /**
     * @test
     */
    public function Excelのアップロードテスト()
    {
        $count = 10;
        $headers = ['標準書式', '日付', '数値を文字で'];
        $fileFactory = new XlsxFileFactory($headers);

        // この処理を行うと「storage/app/public/test.xlsx」が出来上がる
        $fileFactory->createDummyFile($count);

        // アップロードのテスト
        $file = new UploadedFile(
            base_path('storage/app/public/') . 'test.xlsx',
            'test.xlsx',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // MS ExcelのMimeType
            0,
            true // テストフラグをtrueにする
        );

        // POSTのボディ部(フォームデータ)にfileを渡す
        $this->post(route('import'), [
            'import_file' => $file,
        ]);
    }

    public function tearDown(): void
    {
        if (Storage::disk('public')->exists('test.xlsx')) {
            Storage::disk('public')->delete('test.xlsx');
        }
    }
}

tearDownでファイルを消しているので、テストした跡も残らず
GitHubActionsやCircleCI等のテストランナーで活用できるかと思います。
テスト中は、ファイルの中身を見たいシーンもあるでしょうから、コメントアウトしとくと良いですね。

本当はStorageファサードで全部解決できれば良かったのですが
Storage::get()new File()等で取得しようとすると中身のコンテンツがStringで拾われることとなり
テキストデータをPOSTする羽目になってしまったので、今回こういう形になりました。
もっと他に良い方法をご存じの方がいらっしゃれば、ご意見頂きたいと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?