this package can help you to test race condition in Laravel Feature Test

Overview

Laravel Async Testing

Latest Version on Packagist Tests Total Downloads

this package can help you to test race condition in Laravel Feature Test

Async Testing

Requirements

  • Laravel versions 5.7, 6.x, 7.x and 8.x
  • PHP 7.0 or greater

Installation

Install the package with composer:

composer require recca0120/async-testing --dev

Usage

  1. set a real database in phpunit.xml
<phpunit>
    <php>
        <!-- DB_CONNECTION can't be %memory% -->
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value="database/database.sqlite"/>
    </php>
</phpunit>
  1. make a product migration
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->integer('quantity')->default(0);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
}
  1. define product model App\Models\Product
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

/**
 * Class Product.
 * @property int id
 * @property string name
 * @property int quantity
 * @package App\Models
 * @mixin Builder
 */
class Product extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'quantity'];

    protected $casts = ['quantity' => 'int'];
}
  1. define router in routes/web.php
<?php

use App\Models\Product;
use Illuminate\Support\Facades\Route;

Route::get('/product/{productId}', function ($productId) {
    return Product::findOrFail($productId);
});

Route::post('/product/{productId}', function ($productId) {
    $product = Product::findOrFail($productId);
    if ($product->quantity > 0) {
        // wrong, it will make test fail
        // $product->fill(['quantity' => $product->quantity - 1])->save();

        // correct
        $product->where('id', $product->id)
            ->where('quantity', '>', 0)
            ->update(['quantity' => DB::raw('quantity - 1')]);
    }

    return $product->fresh();
});
  1. testing
<?php

namespace Tests\Feature;

use App\Models\Product;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Recca0120\AsyncTesting\AsyncRequest;
use Tests\TestCase;

class RaceConditionTest extends TestCase
{
    use DatabaseMigrations;

    private $product;
    private $quantity = 10;

    public function setUp(): void
    {
        parent::setUp();
        $this->product = Product::create(['name' => 'test', 'quantity' => $this->quantity]);
    }

    public function test_race_condition()
    {
        $asyncRequest = $this->app->make(AsyncRequest::class);

        $promises = collect();
        for ($i = 0; $i < $this->quantity; $i++) {
            // you will get \GuzzleHttp\Promise\PromiseInterface
            $promise = $asyncRequest->post('/product/'.$this->product->id);
            $promises->add($promise);
        }
        // you need wait response
        $promises->map->wait()->each->assertOk();

        $this->get('/product/'.$this->product->id)
            ->assertOk()
            ->assertJsonPath('quantity', 0);
    }

    public function test_use_times_to_test_race_condition()
    {
        $asyncRequest = $this->app->make(AsyncRequest::class);

        $promises = collect($asyncRequest->times(10)->post('/product/'.$this->product->id));

        // you need wait response
        $promises->map->wait()->each->assertOk();

        $this->get('/product/'.$this->product->id)
            ->assertOk()
            ->assertJsonPath('quantity', 0);
    }
}

License

The MIT License (MIT). Please see License File for more information.

You might also like...
This package aims to help you standardize all your API responses in a simple and structured way.

Laravel API Response This package aims to help you standardize all your API responses in a simple and structured way. By default, the stucture of the

Laravel Query Helper was developed for laravel 7.2+ to help you optimize sql queries
Laravel Query Helper was developed for laravel 7.2+ to help you optimize sql queries

Laravel Query Helper Laravel Query Helper was developed for laravel 7.2+ to help you optimize sql queries, this package will contain all advanced SQL

Feature Switching made easy in Laravel 5

Feature Switching (made easy) for Laravel Need to wrap new features for dev and production? Use a directive in the view or alias in the controller The

Cascade delete and restore when using the Laravel or Lumen SoftDeletes feature.
Cascade delete and restore when using the Laravel or Lumen SoftDeletes feature.

Cascade delete and restore when using the Laravel or Lumen SoftDeletes feature.

This template should help get you started developing with laravel 9 + Vue 3 in Vite + Tailwind

simple-project This template should help get you started developing with laravel 9 + Vue 3 in Vite + Tailwind

Easily interact and control your feature flags from Filament

Easily interact and control your feature flags from Filament

PHP package to help the development of Laravel-based Telegram bots
PHP package to help the development of Laravel-based Telegram bots

Laravel-telegram-bot Project description goes here. This description is usually two to three lines long. It should give an overview of what the projec

Laravel Livewire package for clone screen with the help of websocket

screen-wire This is a Laravel Livewire package. It allow you to see what users are doing on their screen. Installation composer require mrbohem/scree

A Laravel package to help track user onboarding steps.
A Laravel package to help track user onboarding steps.

Onboard A Laravel package to help track user onboarding steps. Installation: Install the package via composer composer require calebporzio/onboard Reg

Releases(v1.0.1)
Owner
Recca Tsai
Recca Tsai
Testbench Component is the de-facto package that has been designed to help you write tests for your Laravel package

Laravel Testing Helper for Packages Development Testbench Component is the de-facto package that has been designed to help you write tests for your La

Orchestra Platform 1.9k Dec 29, 2022
CV-Resumes-App is helped us to build resume .. you can help me to improve this app...

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Eng Hasan Hajjar 2 Sep 30, 2022
An opinionated feature flags package for Laravel

This package provides an opinionated API for implementing feature flags in your Laravel applications. It supports application-wide features as well as model specific feature flags.

Ryan Chandler 157 Nov 24, 2022
A package that adds view-composer like feature to Inertia.js Laravel adapter

Kinetic A package that adds view-composer like feature to Inertia.js Laravel adapter. Use to be able to share props based on the Inertia component nam

Marvin Quezon 76 Dec 12, 2022
You already have your dream house? Sam Building will help you find the perfect home.

SAM BUILDING Setup Fork or clone this repo! git clone github.com/Igorballo/Real-Estate-App.git Installation des d├ępendances npm install #or yarn insta

null 4 Nov 29, 2022
Electrik is a full-featured, open-source, starter-kit to help you build you your SaaS application.

Electrik Electrik is a full-featured and open-source stater-kit for for your next SaaS application. It's built on top of Laravel, Livewire, neerajsoha

Electrik 129 Dec 31, 2022
A Laravel chat package. You can use this package to create a chat/messaging Laravel application.

Chat Create a Chat application for your multiple Models Table of Contents Click to expand Introduction Installation Usage Adding the ability to partic

Tinashe Musonza 931 Dec 24, 2022
a Laravel package help you to execute more effective databases queries.

Laravel Query Helper Laravel Query Helper was developed for laravel 7.2+ to help you optimizing sql queries, this package will contain all advanced sq

karam mustafa 9 Jul 26, 2022
This package should help you with creating and managing a Laravel DDD Application

This package should help you with creating and managing a Laravel DDD Application. This package is heavily inspired by "Laravel beyond CRUD" from Spatie.

J. Regner 158 Dec 25, 2022
Relational Metrics - lararvel package help you to make your metrics easier

Relational Metrics This package will help you to make your metrics easier, You could get metrics about your Models, Models depending on their relation

Syrian Open Source 25 Oct 12, 2022