Przeglądaj źródła

单元测试用例兼容laravel8

jqh 4 lat temu
rodzic
commit
8ad4543808

+ 0 - 130
tests/Browser/Cases/OperationLogTest.php

@@ -1,130 +0,0 @@
-<?php
-
-namespace Tests\Browser\Cases;
-
-use Dcat\Admin\Models\OperationLog;
-use Laravel\Dusk\Browser;
-use Tests\Browser\Components\Grid\Actions\BatchDelete;
-use Tests\Browser\Components\Grid\Actions\Delete;
-use Tests\Browser\Components\Grid\BatchActions;
-use Tests\Browser\Components\Grid\RowSelector;
-use Tests\TestCase;
-
-/**
- * 操作日志功能测试.
- *
- * @group log
- */
-class OperationLogTest extends TestCase
-{
-    public function testIndex()
-    {
-        $this->browse(function (Browser $browser) {
-            $browser->visit(admin_base_path('auth/menu'))
-                ->assertPathIs(admin_base_path('auth/menu'))
-                ->visit(admin_base_path('auth/logs'))
-                ->assertSeeText(__('admin.operation_log'))
-                ->assertSeeText(__('admin.list'))
-                ->assertSeeText(__('admin.refresh'))
-                ->assertSeeText(__('admin.filter'))
-                ->assertSeeText('ID')
-                ->assertSeeText((__('admin.user')))
-                ->assertSeeText((__('admin.method')))
-                ->assertSeeText((__('admin.uri')))
-                ->assertSeeText('IP')
-                ->assertSeeText((__('admin.input')))
-                ->assertSeeText((__('admin.created_at')))
-                ->assertSeeText((__('admin.action')))
-                ->waitForText(__('admin.responsive.display'), 2)
-                ->assertSeeText(__('admin.responsive.display_all'));
-        });
-    }
-
-    public function testGenerateLogs()
-    {
-        $this->browse(function (Browser $browser) {
-            $table = config('admin.database.operation_log_table');
-
-            $browser->visit(admin_base_path('auth/menu'))
-                ->assertPathIs(admin_base_path('auth/menu'))
-                ->visit(admin_base_path('auth/users'))
-                ->assertPathIs(admin_base_path('auth/users'))
-                ->visit(admin_base_path('auth/permissions'))
-                ->assertPathIs(admin_base_path('auth/permissions'))
-                ->visit(admin_base_path('auth/roles'))
-                ->assertPathIs(admin_base_path('auth/roles'))
-                ->visit(admin_base_path('auth/logs'))
-                ->assertPathIs(admin_base_path('auth/logs'));
-
-            $this->seeInDatabase($table, ['path' => trim(admin_base_path('auth/menu'), '/'), 'method' => 'GET'])
-                ->seeInDatabase($table, ['path' => trim(admin_base_path('auth/users'), '/'), 'method' => 'GET'])
-                ->seeInDatabase($table, ['path' => trim(admin_base_path('auth/permissions'), '/'), 'method' => 'GET'])
-                ->seeInDatabase($table, ['path' => trim(admin_base_path('auth/roles'), '/'), 'method' => 'GET']);
-        });
-
-        $this->assertSame(4, OperationLog::count());
-    }
-
-    public function testDeleteLogs()
-    {
-        $this->browse(function (Browser $browser) {
-            $table = config('admin.database.operation_log_table');
-
-            $this->assertEquals(0, OperationLog::count());
-
-            $browser->visit(admin_base_path('auth/users'));
-            $this->seeInDatabase($table, ['path' => trim(admin_base_path('auth/users'), '/'), 'method' => 'GET']);
-
-            $browser->visit(admin_base_path('auth/logs'))
-                ->assertPathIs(admin_base_path('auth/logs'))
-                ->pause(500);
-
-            $browser->with(new Delete(), function (Browser $browser) {
-                $browser->delete(0);
-            });
-
-            $this->assertEquals(0, OperationLog::count());
-        });
-    }
-
-    public function testDeleteMultipleLogs()
-    {
-        $this->browse(function (Browser $browser) {
-            $table = config('admin.database.operation_log_table');
-
-            $browser->visit(admin_base_path('auth/menu'))
-                ->visit(admin_base_path('auth/users'))
-                ->visit(admin_base_path('auth/permissions'))
-                ->visit(admin_base_path('auth/roles'));
-
-            $number = 4;
-
-            $this->seeInDatabase($table, ['path' => trim(admin_base_path('auth/menu'), '/'), 'method' => 'GET'])
-                ->seeInDatabase($table, ['path' => trim(admin_base_path('auth/users'), '/'), 'method' => 'GET'])
-                ->seeInDatabase($table, ['path' => trim(admin_base_path('auth/permissions'), '/'), 'method' => 'GET'])
-                ->seeInDatabase($table, ['path' => trim(admin_base_path('auth/roles'), '/'), 'method' => 'GET'])
-                ->assertEquals($number, OperationLog::count());
-
-            $browser->visit(admin_base_path('auth/logs'))
-                ->assertPathIs(admin_base_path('auth/logs'));
-
-            $browser->with(new RowSelector(), function (Browser $browser) {
-                $browser->selectAll();
-            });
-
-            $browser->with(new BatchActions(), function (Browser $browser) use ($number) {
-                $browser->shown($number);
-                $browser->open();
-                $browser->choose(__('admin.delete'));
-            });
-
-            $browser->with(new BatchDelete(), function (Browser $browser) {
-                $browser->waitForConfirmDialog();
-                $browser->clickConfirmButton();
-                $browser->waitForSucceeded();
-            });
-
-            $this->assertEquals(0, OperationLog::count());
-        });
-    }
-}

+ 326 - 0
tests/Factory.php

@@ -0,0 +1,326 @@
+<?php
+
+namespace Tests;
+
+use ArrayAccess;
+use Faker\Generator as Faker;
+use Symfony\Component\Finder\Finder;
+
+class Factory implements ArrayAccess
+{
+    /**
+     * The model definitions in the container.
+     *
+     * @var array
+     */
+    protected $definitions = [];
+
+    /**
+     * The registered model states.
+     *
+     * @var array
+     */
+    protected $states = [];
+
+    /**
+     * The registered after making callbacks.
+     *
+     * @var array
+     */
+    protected $afterMaking = [];
+
+    /**
+     * The registered after creating callbacks.
+     *
+     * @var array
+     */
+    protected $afterCreating = [];
+
+    /**
+     * The Faker instance for the builder.
+     *
+     * @var \Faker\Generator
+     */
+    protected $faker;
+
+    /**
+     * Create a new factory instance.
+     *
+     * @param  \Faker\Generator  $faker
+     * @return void
+     */
+    public function __construct(Faker $faker)
+    {
+        $this->faker = $faker;
+    }
+
+    /**
+     * Create a new factory container.
+     *
+     * @param  \Faker\Generator  $faker
+     * @param  string|null  $pathToFactories
+     * @return static
+     */
+    public static function construct(Faker $faker, $pathToFactories = null)
+    {
+        $pathToFactories = $pathToFactories ?: database_path('factories');
+
+        return (new static($faker))->load($pathToFactories);
+    }
+
+    /**
+     * Define a class with a given short-name.
+     *
+     * @param  string  $class
+     * @param  string  $name
+     * @param  callable  $attributes
+     * @return $this
+     */
+    public function defineAs($class, $name, callable $attributes)
+    {
+        return $this->define($class, $attributes, $name);
+    }
+
+    /**
+     * Define a class with a given set of attributes.
+     *
+     * @param  string  $class
+     * @param  callable  $attributes
+     * @param  string  $name
+     * @return $this
+     */
+    public function define($class, callable $attributes, $name = 'default')
+    {
+        $this->definitions[$class][$name] = $attributes;
+
+        return $this;
+    }
+
+    /**
+     * Define a state with a given set of attributes.
+     *
+     * @param  string  $class
+     * @param  string  $state
+     * @param  callable|array  $attributes
+     * @return $this
+     */
+    public function state($class, $state, $attributes)
+    {
+        $this->states[$class][$state] = $attributes;
+
+        return $this;
+    }
+
+    /**
+     * Define a callback to run after making a model.
+     *
+     * @param  string  $class
+     * @param  callable  $callback
+     * @param  string  $name
+     * @return $this
+     */
+    public function afterMaking($class, callable $callback, $name = 'default')
+    {
+        $this->afterMaking[$class][$name][] = $callback;
+
+        return $this;
+    }
+
+    /**
+     * Define a callback to run after making a model with given state.
+     *
+     * @param  string  $class
+     * @param  string  $state
+     * @param  callable  $callback
+     * @return $this
+     */
+    public function afterMakingState($class, $state, callable $callback)
+    {
+        return $this->afterMaking($class, $callback, $state);
+    }
+
+    /**
+     * Define a callback to run after creating a model.
+     *
+     * @param  string  $class
+     * @param  callable  $callback
+     * @param  string $name
+     * @return $this
+     */
+    public function afterCreating($class, callable $callback, $name = 'default')
+    {
+        $this->afterCreating[$class][$name][] = $callback;
+
+        return $this;
+    }
+
+    /**
+     * Define a callback to run after creating a model with given state.
+     *
+     * @param  string  $class
+     * @param  string  $state
+     * @param  callable  $callback
+     * @return $this
+     */
+    public function afterCreatingState($class, $state, callable $callback)
+    {
+        return $this->afterCreating($class, $callback, $state);
+    }
+
+    /**
+     * Create an instance of the given model and persist it to the database.
+     *
+     * @param  string  $class
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function create($class, array $attributes = [])
+    {
+        return $this->of($class)->create($attributes);
+    }
+
+    /**
+     * Create an instance of the given model and type and persist it to the database.
+     *
+     * @param  string  $class
+     * @param  string  $name
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function createAs($class, $name, array $attributes = [])
+    {
+        return $this->of($class, $name)->create($attributes);
+    }
+
+    /**
+     * Create an instance of the given model.
+     *
+     * @param  string  $class
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function make($class, array $attributes = [])
+    {
+        return $this->of($class)->make($attributes);
+    }
+
+    /**
+     * Create an instance of the given model and type.
+     *
+     * @param  string  $class
+     * @param  string  $name
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function makeAs($class, $name, array $attributes = [])
+    {
+        return $this->of($class, $name)->make($attributes);
+    }
+
+    /**
+     * Get the raw attribute array for a given named model.
+     *
+     * @param  string  $class
+     * @param  string  $name
+     * @param  array  $attributes
+     * @return array
+     */
+    public function rawOf($class, $name, array $attributes = [])
+    {
+        return $this->raw($class, $attributes, $name);
+    }
+
+    /**
+     * Get the raw attribute array for a given model.
+     *
+     * @param  string  $class
+     * @param  array  $attributes
+     * @param  string  $name
+     * @return array
+     */
+    public function raw($class, array $attributes = [], $name = 'default')
+    {
+        return array_merge(
+            call_user_func($this->definitions[$class][$name], $this->faker), $attributes
+        );
+    }
+
+    /**
+     * Create a builder for the given model.
+     *
+     * @param  string  $class
+     * @param  string  $name
+     * @return FactoryBuilder
+     */
+    public function of($class, $name = 'default')
+    {
+        return new FactoryBuilder(
+            $class, $name, $this->definitions, $this->states,
+            $this->afterMaking, $this->afterCreating, $this->faker
+        );
+    }
+
+    /**
+     * Load factories from path.
+     *
+     * @param  string  $path
+     * @return $this
+     */
+    public function load($path)
+    {
+        $factory = $this;
+
+        if (is_dir($path)) {
+            foreach (Finder::create()->files()->name('*.php')->in($path) as $file) {
+                require $file->getRealPath();
+            }
+        }
+
+        return $factory;
+    }
+
+    /**
+     * Determine if the given offset exists.
+     *
+     * @param  string  $offset
+     * @return bool
+     */
+    public function offsetExists($offset)
+    {
+        return isset($this->definitions[$offset]);
+    }
+
+    /**
+     * Get the value of the given offset.
+     *
+     * @param  string  $offset
+     * @return mixed
+     */
+    public function offsetGet($offset)
+    {
+        return $this->make($offset);
+    }
+
+    /**
+     * Set the given offset to the given value.
+     *
+     * @param  string  $offset
+     * @param  callable  $value
+     * @return void
+     */
+    public function offsetSet($offset, $value)
+    {
+        $this->define($offset, $value);
+    }
+
+    /**
+     * Unset the value at the given offset.
+     *
+     * @param  string  $offset
+     * @return void
+     */
+    public function offsetUnset($offset)
+    {
+        unset($this->definitions[$offset]);
+    }
+}

+ 446 - 0
tests/FactoryBuilder.php

@@ -0,0 +1,446 @@
+<?php
+
+namespace Tests;
+
+use Faker\Generator as Faker;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Traits\Macroable;
+use InvalidArgumentException;
+
+class FactoryBuilder
+{
+    use Macroable;
+
+    /**
+     * The model definitions in the container.
+     *
+     * @var array
+     */
+    protected $definitions;
+
+    /**
+     * The model being built.
+     *
+     * @var string
+     */
+    protected $class;
+
+    /**
+     * The name of the model being built.
+     *
+     * @var string
+     */
+    protected $name = 'default';
+
+    /**
+     * The database connection on which the model instance should be persisted.
+     *
+     * @var string
+     */
+    protected $connection;
+
+    /**
+     * The model states.
+     *
+     * @var array
+     */
+    protected $states;
+
+    /**
+     * The model after making callbacks.
+     *
+     * @var array
+     */
+    protected $afterMaking = [];
+
+    /**
+     * The model after creating callbacks.
+     *
+     * @var array
+     */
+    protected $afterCreating = [];
+
+    /**
+     * The states to apply.
+     *
+     * @var array
+     */
+    protected $activeStates = [];
+
+    /**
+     * The Faker instance for the builder.
+     *
+     * @var \Faker\Generator
+     */
+    protected $faker;
+
+    /**
+     * The number of models to build.
+     *
+     * @var int|null
+     */
+    protected $amount = null;
+
+    /**
+     * Create an new builder instance.
+     *
+     * @param  string  $class
+     * @param  string  $name
+     * @param  array  $definitions
+     * @param  array  $states
+     * @param  array  $afterMaking
+     * @param  array  $afterCreating
+     * @param  \Faker\Generator  $faker
+     * @return void
+     */
+    public function __construct($class, $name, array $definitions, array $states,
+        array $afterMaking, array $afterCreating, Faker $faker)
+    {
+        $this->name = $name;
+        $this->class = $class;
+        $this->faker = $faker;
+        $this->states = $states;
+        $this->definitions = $definitions;
+        $this->afterMaking = $afterMaking;
+        $this->afterCreating = $afterCreating;
+    }
+
+    /**
+     * Set the amount of models you wish to create / make.
+     *
+     * @param  int  $amount
+     * @return $this
+     */
+    public function times($amount)
+    {
+        $this->amount = $amount;
+
+        return $this;
+    }
+
+    /**
+     * Set the state to be applied to the model.
+     *
+     * @param  string  $state
+     * @return $this
+     */
+    public function state($state)
+    {
+        return $this->states([$state]);
+    }
+
+    /**
+     * Set the states to be applied to the model.
+     *
+     * @param  array|mixed  $states
+     * @return $this
+     */
+    public function states($states)
+    {
+        $this->activeStates = is_array($states) ? $states : func_get_args();
+
+        return $this;
+    }
+
+    /**
+     * Set the database connection on which the model instance should be persisted.
+     *
+     * @param  string  $name
+     * @return $this
+     */
+    public function connection($name)
+    {
+        $this->connection = $name;
+
+        return $this;
+    }
+
+    /**
+     * Create a model and persist it in the database if requested.
+     *
+     * @param  array  $attributes
+     * @return \Closure
+     */
+    public function lazy(array $attributes = [])
+    {
+        return function () use ($attributes) {
+            return $this->create($attributes);
+        };
+    }
+
+    /**
+     * Create a collection of models and persist them to the database.
+     *
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function create(array $attributes = [])
+    {
+        $results = $this->make($attributes);
+
+        if ($results instanceof Model) {
+            $this->store(collect([$results]));
+
+            $this->callAfterCreating(collect([$results]));
+        } else {
+            $this->store($results);
+
+            $this->callAfterCreating($results);
+        }
+
+        return $results;
+    }
+
+    /**
+     * Set the connection name on the results and store them.
+     *
+     * @param  \Illuminate\Support\Collection  $results
+     * @return void
+     */
+    protected function store($results)
+    {
+        $results->each(function ($model) {
+            if (! isset($this->connection)) {
+                $model->setConnection($model->newQueryWithoutScopes()->getConnection()->getName());
+            }
+
+            $model->save();
+        });
+    }
+
+    /**
+     * Create a collection of models.
+     *
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function make(array $attributes = [])
+    {
+        if ($this->amount === null) {
+            return tap($this->makeInstance($attributes), function ($instance) {
+                $this->callAfterMaking(collect([$instance]));
+            });
+        }
+
+        if ($this->amount < 1) {
+            return (new $this->class)->newCollection();
+        }
+
+        $instances = (new $this->class)->newCollection(array_map(function () use ($attributes) {
+            return $this->makeInstance($attributes);
+        }, range(1, $this->amount)));
+
+        $this->callAfterMaking($instances);
+
+        return $instances;
+    }
+
+    /**
+     * Create an array of raw attribute arrays.
+     *
+     * @param  array  $attributes
+     * @return mixed
+     */
+    public function raw(array $attributes = [])
+    {
+        if ($this->amount === null) {
+            return $this->getRawAttributes($attributes);
+        }
+
+        if ($this->amount < 1) {
+            return [];
+        }
+
+        return array_map(function () use ($attributes) {
+            return $this->getRawAttributes($attributes);
+        }, range(1, $this->amount));
+    }
+
+    /**
+     * Get a raw attributes array for the model.
+     *
+     * @param  array  $attributes
+     * @return mixed
+     *
+     * @throws \InvalidArgumentException
+     */
+    protected function getRawAttributes(array $attributes = [])
+    {
+        if (! isset($this->definitions[$this->class][$this->name])) {
+            throw new InvalidArgumentException("Unable to locate factory with name [{$this->name}] [{$this->class}].");
+        }
+
+        $definition = call_user_func(
+            $this->definitions[$this->class][$this->name],
+            $this->faker, $attributes
+        );
+
+        return $this->expandAttributes(
+            array_merge($this->applyStates($definition, $attributes), $attributes)
+        );
+    }
+
+    /**
+     * Make an instance of the model with the given attributes.
+     *
+     * @param  array  $attributes
+     * @return \Illuminate\Database\Eloquent\Model
+     */
+    protected function makeInstance(array $attributes = [])
+    {
+        return Model::unguarded(function () use ($attributes) {
+            $instance = new $this->class(
+                $this->getRawAttributes($attributes)
+            );
+
+            if (isset($this->connection)) {
+                $instance->setConnection($this->connection);
+            }
+
+            return $instance;
+        });
+    }
+
+    /**
+     * Apply the active states to the model definition array.
+     *
+     * @param  array  $definition
+     * @param  array  $attributes
+     * @return array
+     *
+     * @throws \InvalidArgumentException
+     */
+    protected function applyStates(array $definition, array $attributes = [])
+    {
+        foreach ($this->activeStates as $state) {
+            if (! isset($this->states[$this->class][$state])) {
+                if ($this->stateHasAfterCallback($state)) {
+                    continue;
+                }
+
+                throw new InvalidArgumentException("Unable to locate [{$state}] state for [{$this->class}].");
+            }
+
+            $definition = array_merge(
+                $definition,
+                $this->stateAttributes($state, $attributes)
+            );
+        }
+
+        return $definition;
+    }
+
+    /**
+     * Get the state attributes.
+     *
+     * @param  string  $state
+     * @param  array  $attributes
+     * @return array
+     */
+    protected function stateAttributes($state, array $attributes)
+    {
+        $stateAttributes = $this->states[$this->class][$state];
+
+        if (! is_callable($stateAttributes)) {
+            return $stateAttributes;
+        }
+
+        return $stateAttributes($this->faker, $attributes);
+    }
+
+    /**
+     * Expand all attributes to their underlying values.
+     *
+     * @param  array  $attributes
+     * @return array
+     */
+    protected function expandAttributes(array $attributes)
+    {
+        foreach ($attributes as &$attribute) {
+            if (is_callable($attribute) && ! is_string($attribute) && ! is_array($attribute)) {
+                $attribute = $attribute($attributes);
+            }
+
+            if ($attribute instanceof static) {
+                $attribute = $attribute->create()->getKey();
+            }
+
+            if ($attribute instanceof Model) {
+                $attribute = $attribute->getKey();
+            }
+        }
+
+        return $attributes;
+    }
+
+    /**
+     * Run after making callbacks on a collection of models.
+     *
+     * @param  \Illuminate\Support\Collection  $models
+     * @return void
+     */
+    public function callAfterMaking($models)
+    {
+        $this->callAfter($this->afterMaking, $models);
+    }
+
+    /**
+     * Run after creating callbacks on a collection of models.
+     *
+     * @param  \Illuminate\Support\Collection  $models
+     * @return void
+     */
+    public function callAfterCreating($models)
+    {
+        $this->callAfter($this->afterCreating, $models);
+    }
+
+    /**
+     * Call after callbacks for each model and state.
+     *
+     * @param  array  $afterCallbacks
+     * @param  \Illuminate\Support\Collection  $models
+     * @return void
+     */
+    protected function callAfter(array $afterCallbacks, $models)
+    {
+        $states = array_merge([$this->name], $this->activeStates);
+
+        $models->each(function ($model) use ($states, $afterCallbacks) {
+            foreach ($states as $state) {
+                $this->callAfterCallbacks($afterCallbacks, $model, $state);
+            }
+        });
+    }
+
+    /**
+     * Call after callbacks for each model and state.
+     *
+     * @param  array  $afterCallbacks
+     * @param  \Illuminate\Database\Eloquent\Model  $model
+     * @param  string  $state
+     * @return void
+     */
+    protected function callAfterCallbacks(array $afterCallbacks, $model, $state)
+    {
+        if (! isset($afterCallbacks[$this->class][$state])) {
+            return;
+        }
+
+        foreach ($afterCallbacks[$this->class][$state] as $callback) {
+            $callback($model, $this->faker);
+        }
+    }
+
+    /**
+     * Determine if the given state has an "after" callback.
+     *
+     * @param  string  $state
+     * @return bool
+     */
+    protected function stateHasAfterCallback($state)
+    {
+        return isset($this->afterMaking[$this->class][$state]) ||
+            isset($this->afterCreating[$this->class][$state]);
+    }
+}

+ 1 - 1
tests/resources/seeds/factory.php

@@ -1,7 +1,7 @@
 <?php
 
 use Faker\Generator as Faker;
-use Illuminate\Database\Eloquent\Factory;
+use Tests\Factory;
 
 $factory = app(Factory::class);