PHPUnit機能テストでクラスをオーバーライドする

アルベルトスキー

複数のことを実行し、最後にcsvインポートを実行するカスタムArtisanコマンドをテストしようとしています。new CsvDirectDatabaseImporterartisanコマンド内でオブジェクトを手動でインスタンス化しますこれは、SQLiteでサポートされていないimport()を使用しLOAD DATA LOCAL INFILEcsvからデータベースにインポートするというメソッドを実行しますテストをメモリ内で実行したいので、CsvDirectDatabaseImporterクラスのimportメソッドをオーバーライド(またはモック/スタブで正しい用語がわからない)して、インポート呼び出し中に何も実行しないようにします。このようにして、残りのテストが機能します(実際のインポートをテストしていないことがわかりました)これを回避するにはどうすればよいですか?

これが私の職人クラスの簡略版です:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use App\Services\CsvDirectDatabaseImporter\CsvDirectDatabaseImporter;
use App\Services\CsvDirectDatabaseImporter\MyColumns;

class DataMartImport extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'myimport:import
                            {year : The year of processing} ';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'My Import';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $year = $this->argument('year');

        // Copy the file to processing location.
        File::copy($files[0], $processing_file);

        // Import the CSV File.
        $csvImporter = new CsvDirectDatabaseImporter($processing_file, 'myTable', new MyColumns());
        $csvImporter->import();
    }

}

カスタム職人コマンドを実行する機能テストの簡略版:

<?php

namespace Tests\Feature\Console\DataMart;

use Illuminate\Support\Facades\File;
use Tests\TestCase;
use Illuminate\Support\Facades\Config;
use Mockery as m;
use App\Services\CsvDirectDatabaseImporter\DataMartColumns;
use App\Services\CsvDirectDatabaseImporter\CsvDirectDatabaseImporter;
use Illuminate\Support\Facades\Artisan;

class MyImportTest extends TestCase
{


    public function testImportFoldersGetCreatedIfNoDirectory()
    {
        $year = 2019;

        $this->artisan('myimport:import', ['year' => $year]);

        // Assertions of items go here unrelated to the actual database import.
    }

}

CSVImorterクラス

<?php

namespace App\Services\CsvDirectDatabaseImporter;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Symfony\Component\HttpFoundation\File\File as CSV_File;

class CsvDirectDatabaseImporter {

    /**
     * File to import.
     *
     * @var \Symfony\Component\HttpFoundation\File\File
     */
    private $file;

    /**
     * Table name.
     *
     * @var string
     */
    private $table;

    /**
     * Fields terminated by.
     *
     * @var string
     */
    public $fieldsTerminatedBy = '\',\'';

    /**
     * Enclosed by.
     *
     * @var string
     */
    public $enclosedBy = '\'"\'';

    /**
     * Lines terminated by.
     *
     * @var string
     */
    public $linesTerminatedBy = '\'\n\'';

    /**
     * Ignore first row.
     *
     * @var bool
     */
    public $ignoreFirstRow = true;

    /**
     * Csv Import columns.
     *
     * @var array
     */
    public $columns;

    /**
     * CsvImporter constructor.
     *
     * @param string $path
     *   The full temporary path to the file
     */
    public function __construct(string $path, $table, CsvDirectDatabaseImportColumns $columns)
    {
        $this->file = new CSV_File($path);
        $this->table = $table;
        $this->columns = $columns->getColumns();
    }

    /**
     * Import method used for saving file and importing it using database query.
     */
    public function import()
    {
        // Normalize line endings
        $normalized_file = $this->normalize($this->file);

        // Import contents of the file into database
        return $this->importFileContents($normalized_file, $this->table, $this->columns);
    }

    /**
     * Convert file line endings to uniform "\r\n" to solve for EOL issues
     * Files that are created on different platforms use different EOL characters
     * This method will convert all line endings to Unix uniform
     *
     * @param string $file_path
     * @return string $file_path
     */
    protected function normalize($file_path)
    {
        // Load the file into a string.
        $string = @file_get_contents($file_path);

        if (!$string) {
            return $file_path;
        }

        // Convert all line-endings using regular expression.
        $string = preg_replace('~\r\n?~', "\n", $string);

        file_put_contents($file_path, $string);

        return $file_path;
    }

    /**
     * Import CSV file into Database using LOAD DATA LOCAL INFILE function
     *
     * NOTE: PDO settings must have attribute PDO::MYSQL_ATTR_LOCAL_INFILE => true
     *
     * @param string $file_path
     *   File path.
     * @param string $table_name
     *   Table name.
     * @param array $columns
     *   Array of columns.
     *
     * @return mixed Will return number of lines imported by the query
     */
    private function importFileContents($file_path, $table_name, $columns)
    {
        $prefix = config('database.connections.mysql.prefix');
        $query = '
            LOAD DATA LOCAL INFILE \'' . $file_path . '\' INTO TABLE `' . $prefix . $table_name . '`
            FIELDS TERMINATED BY ' . $this->fieldsTerminatedBy . '
            ENCLOSED BY ' . $this->enclosedBy . '
            LINES TERMINATED BY ' . $this->linesTerminatedBy . '
            ';
        if ($this->ignoreFirstRow) {
            $query .= ' IGNORE 1 ROWS ';
        }

        if ($columns) {
            $query .= '(' . implode(",\n", array_keys($columns)) . ')';

            $query .= "\nSET \n";

            $sets = [];
            foreach ($columns as $column) {
                $sets[] = $column['name'] . ' = ' . $column['set'];
            }
            $query .= implode(",\n", $sets);
        }

        return DB::connection()->getPdo()->exec($query);
    }
}

CsvDirectDatabaseImportColumnsインターフェイス

<?php

namespace App\Services\CsvDirectDatabaseImporter;

interface CsvDirectDatabaseImportColumns
{

    /**
     * Returns array of columns.
     *
     * Ex:
     *   '@user_id' => [
     *     'name' =>  'user_id',
     *     'set' => '@user_id',
     *   ],
     *   '@agent_number' => [
     *     'name' =>  'agent_number',
     *     'set' => 'LEFT(@agent_number, 7)',
     *   ],
     *
     * The key should be the column name of the csv but add @ in front. The name
     * will be the database table.  The set will be what it s se
     *
     * @return array
     */
    public function columns();

    /**
     * Returns columns.
     *
     * @return array
     *   Columns.
     */
    public function getColumns();
}

試したこと

$mock = $this->createMock(CsvDirectDatabaseImporter::class);
        $mock->method('import')->willReturn(true);
        $this->app->instance(CsvDirectDatabaseImporter::class, $mock);
$this->artisan('datamart:import', ['year' => $year]);

しかし、そこには運がありません。それでも通常のimport()メソッドを実行します。

サリム・ジャーボウ

だから私はあなたが必要だと思うものを簡単な例に再現しようとしました

このコマンドがあるとしましょう

<?php

namespace App\Console\Commands;

use Exception;
use Illuminate\Console\Command;

class Foo extends Command
{
    protected $signature = 'foo';

    public function __construct()
    {
        parent::__construct();
    }
    public function handle()
    {
        if ($this->import()) {
            $this->info('Success');
        } else {
            $this->error('Failed');
        }
    }

    public function import()
    {
        throw new Exception('An exception that should not be thrown');
    }
}

importメソッドは例外をスローしますが、trueを返すようにモックする方法は次のとおりです。

<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Console\Commands\Foo;

class FooCommandTest extends TestCase
{
    public function testExample()
    {
        $mock = $this->getMockBuilder(Foo::class)->setMethods(['import'])->getMock();
        $mock->method('import')->willReturn(true);
        $this->app->instance('App\Console\Commands\Foo', $mock);
        $this->artisan('foo')
            ->expectsOutput('Success')
            ->assertExitCode(0);
    }
}

このテストは2つの成功したアサーションで合格するため、インポート専用のメソッドを使用するようにコマンドコードを調整できます。

お役に立てれば

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

単体テストでsettings.pyOBJECTをオーバーライドするDjangoが機能しない

分類Dev

phpunitテストでzf2モジュール構成をオーバーライドする

分類Dev

mathjaxアクセシビリティブルーボックス機能をオーバーライドする

分類Dev

インテントエクストラをオーバーライドする

分類Dev

DAOクラスをオーバーライドするSpringFramework統合テスト

分類Dev

PHPUnitテストでLaravelの例外ハンドラーをオーバーライドするにはどうすればよいですか?

分類Dev

基本クラスの非抽象メソッドをオーバーライドする機能がある理由

分類Dev

Javascriptでネイティブコンストラクターをオーバーライドする方法

分類Dev

ドラッグイベントリスナーをChrome拡張機能(コンテンツスクリプト)でオーバーライドするにはどうすればよいですか?

分類Dev

マテリアルUIコンポーネントをSASSクラスでオーバーライドする

分類Dev

テンプレート関数を抽象クラスでオーバーライドする

分類Dev

%nをオーバーライドしてルートシェルを生成するSetuidバイナリ。エクスプロイトでは機能しませんが、エクスプロイトが不要な場合は機能します

分類Dev

スーパークラスのhashCodeとオブジェクトでhashCodeをオーバーライドする

分類Dev

コンテキストをオーバーライドします。プロパティと機能

分類Dev

WPFでOnDrawItemリストボックスをオーバーライドする

分類Dev

特定のクラスのTextField機能をオーバーライドする方法は?

分類Dev

IsValidをオーバーライドするValidationAttributeのテスト

分類Dev

基本クラスのフィールド機能をオーバーライドするにはどうすればよいですか?

分類Dev

Python:インポートされたクラスをオーバーライドして機能を拡張する

分類Dev

2番目のテスト機能でエラーを与えるPhpUnit

分類Dev

WebでオーディオAPIの使用を開始する:コードはデスクトップブラウザーで機能していますが、モバイルブラウザーでは機能していません

分類Dev

カスタムtypescriptクラスでjavascriptオブジェクトtoString()をオーバーライドする

分類Dev

テスト対象のクラスの呼び出し元である単体テストのメソッドをオーバーライドする方法

分類Dev

Linuxcshスクリプトで$ _の値をオーバーライドする

分類Dev

単体テストでIOスケジューラをオーバーライドするRxJava2

分類Dev

サードパーティのライブラリクラスのXmlAdapterをオーバーライドする

分類Dev

gtestでの単体テストのために、クラス内のプライベートメンバーオブジェクトの機能を置き換えるためのモッククラス/オブジェクトを作成できません

分類Dev

Javaでプロセスクラスをオーバーライドする

分類Dev

クラスがクラスを継承する場合、メソッドのオーバーライドはどのように機能しますか?

Related 関連記事

  1. 1

    単体テストでsettings.pyOBJECTをオーバーライドするDjangoが機能しない

  2. 2

    phpunitテストでzf2モジュール構成をオーバーライドする

  3. 3

    mathjaxアクセシビリティブルーボックス機能をオーバーライドする

  4. 4

    インテントエクストラをオーバーライドする

  5. 5

    DAOクラスをオーバーライドするSpringFramework統合テスト

  6. 6

    PHPUnitテストでLaravelの例外ハンドラーをオーバーライドするにはどうすればよいですか?

  7. 7

    基本クラスの非抽象メソッドをオーバーライドする機能がある理由

  8. 8

    Javascriptでネイティブコンストラクターをオーバーライドする方法

  9. 9

    ドラッグイベントリスナーをChrome拡張機能(コンテンツスクリプト)でオーバーライドするにはどうすればよいですか?

  10. 10

    マテリアルUIコンポーネントをSASSクラスでオーバーライドする

  11. 11

    テンプレート関数を抽象クラスでオーバーライドする

  12. 12

    %nをオーバーライドしてルートシェルを生成するSetuidバイナリ。エクスプロイトでは機能しませんが、エクスプロイトが不要な場合は機能します

  13. 13

    スーパークラスのhashCodeとオブジェクトでhashCodeをオーバーライドする

  14. 14

    コンテキストをオーバーライドします。プロパティと機能

  15. 15

    WPFでOnDrawItemリストボックスをオーバーライドする

  16. 16

    特定のクラスのTextField機能をオーバーライドする方法は?

  17. 17

    IsValidをオーバーライドするValidationAttributeのテスト

  18. 18

    基本クラスのフィールド機能をオーバーライドするにはどうすればよいですか?

  19. 19

    Python:インポートされたクラスをオーバーライドして機能を拡張する

  20. 20

    2番目のテスト機能でエラーを与えるPhpUnit

  21. 21

    WebでオーディオAPIの使用を開始する:コードはデスクトップブラウザーで機能していますが、モバイルブラウザーでは機能していません

  22. 22

    カスタムtypescriptクラスでjavascriptオブジェクトtoString()をオーバーライドする

  23. 23

    テスト対象のクラスの呼び出し元である単体テストのメソッドをオーバーライドする方法

  24. 24

    Linuxcshスクリプトで$ _の値をオーバーライドする

  25. 25

    単体テストでIOスケジューラをオーバーライドするRxJava2

  26. 26

    サードパーティのライブラリクラスのXmlAdapterをオーバーライドする

  27. 27

    gtestでの単体テストのために、クラス内のプライベートメンバーオブジェクトの機能を置き換えるためのモッククラス/オブジェクトを作成できません

  28. 28

    Javaでプロセスクラスをオーバーライドする

  29. 29

    クラスがクラスを継承する場合、メソッドのオーバーライドはどのように機能しますか?

ホットタグ

アーカイブ