PHP项目Laravel HTTP测试请求伪造

wen PHP项目 6

Laravel HTTP测试请求伪造详解

在Laravel中,HTTP测试请求伪造主要涉及如何模拟不同的HTTP请求方法和请求数据,以下是详细的实现方法:

PHP项目Laravel HTTP测试请求伪造

基础请求方法伪造

<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class HttpRequestTest extends TestCase
{
    use RefreshDatabase;
    /** @test */
    public function test_basic_http_requests()
    {
        // GET请求
        $response = $this->get('/api/users');
        // POST请求
        $response = $this->post('/api/users', [
            'name' => 'John Doe',
            'email' => 'john@example.com'
        ]);
        // PUT请求
        $response = $this->put('/api/users/1', [
            'name' => 'Jane Doe'
        ]);
        // PATCH请求
        $response = $this->patch('/api/users/1', [
            'email' => 'jane@example.com'
        ]);
        // DELETE请求
        $response = $this->delete('/api/users/1');
        // 断言状态码
        $response->assertStatus(200);
    }
}

高级请求伪造

<?php
namespace Tests\Feature;
use Tests\TestCase;
class AdvancedHttpRequestTest extends TestCase
{
    /** @test */
    public function test_advanced_request_methods()
    {
        // 带JSON头部的请求
        $response = $this->withHeaders([
            'accept' => 'application/json',
            'X-CSRF-TOKEN' => csrf_token(),
        ])->post('/api/login', [
            'email' => 'user@example.com',
            'password' => 'secret'
        ]);
        // 伪造Ajax请求
        $response = $this->call(
            'POST',
            '/api/data',
            [],
            [],
            [],
            ['HTTP_X-Requested-With' => 'XMLHttpRequest']
        );
        // 带会话的请求
        $response = $this->withSession([
            'user_id' => 1,
            'role' => 'admin'
        ])->get('/admin/dashboard');
        // 带查询参数的GET请求
        $response = $this->get('/api/search', [
            'q' => 'laravel',
            'per_page' => 20
        ]);
    }
    /** @test */
    public function test_request_with_files()
    {
        // 文件上传请求
        $response = $this->post('/api/upload', [
            'file' => UploadedFile::fake()->image('avatar.jpg', 200, 200)
        ]);
        // 多个文件上传
        $response = $this->post('/api/multiple-upload', [
            'files' => [
                UploadedFile::fake()->image('image1.jpg'),
                UploadedFile::fake()->image('image2.jpg')
            ]
        ]);
    }
}

路由固定的请求伪造

<?php
namespace Tests\Feature;
use Tests\TestCase;
class RouteSpecificTest extends TestCase
{
    /** @test */
    public function test_route_specific_requests()
    {
        // 使用路由名称生成请求URL
        $response = $this->post(route('users.store'), [
            'name' => 'John',
            'email' => 'john@example.com'
        ]);
        // 带路由参数的请求
        $response = $this->withMiddleware('auth')
            ->get(route('users.show', ['id' => 1]));
        // 带空间参数的POST请求
        $response = $this->post(route('users.update', ['user' => 1]), [
            'name' => 'Updated Name'
        ]);
        // JSON API请求
        $response = $this->postJson('/api/v1/users', [
            'name' => 'Jane',
            'email' => 'jane@example.com'
        ]);
    }
}

模拟认证用户

<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\User;
use Laravel\Sanctum\Sanctum;
class AuthenticatedRequestTest extends TestCase
{
    /** @test */
    public function test_authenticated_requests()
    {
        $user = User::factory()->create();
        // 使用actingAs助手方法
        $response = $this->actingAs($user)
            ->get('/dashboard');
        // 指定守卫
        $response = $this->actingAs($user, 'admin')
            ->get('/admin/dashboard');
        // Sanctum API认证
        Sanctum::actingAs($user, ['view-api']);
        $response = $this->getJson('/api/users');
        // 带Bearer Token的请求
        $token = $user->createToken('api-token')->plainTextToken;
        $response = $this->withToken($token)
            ->getJson('/api/user');
    }
}

模拟请求头和IP地址

<?php
namespace Tests\Feature;
use Tests\TestCase;
class HeaderIpTest extends TestCase
{
    /** @test */
    public function test_custom_headers_and_ip()
    {
        // 自定义头部
        $response = $this->withHeaders([
            'Authorization' => 'Bearer token123',
            'X-API-Key' => 'abcdef123456',
            'User-Agent' => 'CustomAgent/1.0'
        ])->get('/api/data');
        // 模拟IP地址
        $response = $this->call(
            'GET',
            '/api/geo', 
            [], 
            [], 
            [], 
            [
                'REMOTE_ADDR' => '192.168.1.100',
                'HTTP_X_FORWARDED_FOR' => '203.0.113.1'
            ]
        );
        // 使用withServerVariables
        $response = $this->withServerVariables([
            'REMOTE_ADDR' => '10.0.0.1',
            'HTTP_USER_AGENT' => 'TestBrowser/1.0'
        ])->post('/api/submit');
    }
}

复杂业务场景测试

<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\Order;
use App\Models\User;
use Illuminate\Foundation\Testing\WithFaker;
class ComplexScenarioTest extends TestCase
{
    use WithFaker;
    /** @test */
    public function test_typical_api_workflow()
    {
        // 创建数据
        $user = User::factory()->create();
        $order = Order::factory()->create(['user_id' => $user->id]);
        // 1. 登录获取Token
        $loginResponse = $this->postJson('/api/login', [
            'email' => $user->email,
            'password' => 'password123'
        ]);
        $token = $loginResponse->json('data.token');
        // 2. 使用Token请求数据
        $orderResponse = $this->withHeaders([
            'Authorization' => 'Bearer ' . $token,
            'Accept' => 'application/json'
        ])->getJson("/api/orders/{$order->id}");
        $orderResponse->assertOk()
            ->assertJsonStructure([
                'data' => [
                    'id',
                    'total',
                    'status'
                ]
            ]);
        // 3. 提交复杂请求数据
        $createResponse = $this->postJson('/api/orders', [
            'customer_name' => $this->faker->name(),
            'items' => [
                ['product_id' => 1, 'quantity' => 2],
                ['product_id' => 2, 'quantity' => 1]
            ],
            'shipping_address' => [
                'street' => $this->faker->streetAddress(),
                'city' => $this->faker->city(),
                'zip' => $this->faker->postcode()
            ]
        ]);
        $createResponse->assertStatus(201);
    }
}

测试JSON和XML请求

<?php
namespace Tests\Feature;
use Tests\TestCase;
class JsonXmlTest extends TestCase
{
    /** @test */
    public function test_json_and_xml_requests()
    {
        // JSON请求
        $jsonResponse = $this->postJson('/api/users', [
            'name' => 'John',
            'email' => 'john@example.com'
        ]);
        $jsonResponse->assertJson([
            'success' => true
        ]);
        // XML请求(需要自定义)
        $xmlResponse = $this->call(
            'POST',
            '/api/xml-handler',
            [],
            [],
            [],
            ['CONTENT_TYPE' => 'application/xml'],
            '<root><name>John</name></root>'
        );
        // 断言JSON结构
        $this->postJson('/api/users')
            ->assertJsonStructure([
                'data' => [
                    '*' => [
                        'id',
                        'name',
                        'email'
                    ]
                ]
            ]);
        // 断言部分JSON
        $this->getJson('/api/users/1')
            ->assertJsonFragment([
                'name' => 'John Doe'
            ]);
    }
}

请求伪造的最佳实践

<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class BestPracticesTest extends TestCase
{
    use RefreshDatabase;
    /**
     * 使用辅助方法封装请求
     */
    private function authenticateAndGetUser()
    {
        $user = \App\Models\User::factory()->create([
            'email' => 'test@example.com',
            'password' => bcrypt('password')
        ]);
        $token = $user->createToken('test')->plainTextToken;
        return [$user, $token];
    }
    /** @test */
    public function test_best_practices()
    {
        // 1. 为测试创建数据工厂
        $user = \App\Models\User::factory()->create();
        $order = \App\Models\Order::factory()
            ->for($user)
            ->create();
        // 2. 定义明确的测试意图
        $this->withoutExceptionHandling(); // 调试时使用
        // 3. 使用数据库事务
        $response = $this->transact(function () {
            return $this->post('/api/users', [
                'name' => 'John',
                'email' => 'john@example.com'
            ]);
        });
        // 4. 建立测试环境配置
        $this->app['config']->set('api-timeout', 30);
        // 5. 使用数据提供者进行多场景测试
        $responses = collect([
            ['name' => 'John', 'email' => 'john@example.com'],
            ['name' => 'Jane', 'email' => 'jane@example.com']
        ])->map(function ($data) {
            return $this->post('/api/users', $data);
        });
        $responses->each(function ($response) {
            $response->assertStatus(201);
        });
    }
}

总结关键点:

  1. get()/post()/put()/patch()/delete() 是基本的请求方法
  2. postJson()/getJson() 用于JSON API请求
  3. actingAs() 模拟认证用户
  4. withHeaders() 设置请求头部
  5. withSession() 模拟会话数据
  6. call() 提供更底层的请求控制
  7. UploadedFile::fake() 模拟文件上传
  8. Sanctum::actingAs() 用于API认证测试

这些方法组合使用可以覆盖绝大多数HTTP测试场景。

抱歉,评论功能暂时关闭!