HTTP测试访问应用程序的URL花费太长时间。

huangapple go评论57阅读模式
英文:

http test taking to long to visit a url from application

问题

以下是您要翻译的代码部分:

public function testUserListById()
{
    $user = User::factory()->create();

    $content = $this->actingAs($user)
        ->json('get', route('users.list'))
        ->assertStatus(200)
        ->getContent();

    $content = json_decode($content, true);

    assertTrue(count($content) >= 0);
}
PASS  Tests\Feature\Users\UsersTest
✓ user list by id                           1.78s  

Tests:    1 passed (2 assertions)
Duration: 1.99s
use App\Models\User;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    protected $seed = true;

    protected function setUp(): void
    {
        ini_set('memory_limit', -1);

        parent::setUp(); 
    }
}
英文:

I have an HTTP test that is visiting a users list:

public function testUserListById()
{
    $user = User::factory()->create();

    $content = $this->actingAs($user)
        ->json('get', route('users.list'))
        ->assertStatus(200)
        ->getContent();

    $content = json_decode($content, true);

    assertTrue(count($content) >= 0);
}

The problem is that when I visit the API in postman it takes 400ms to visit that but in my test when I run it:

PASS  Tests\Feature\Users\UsersTest
✓ user list by id                           1.78s  

Tests:    1 passed (2 assertions)
Duration: 1.99s

It takes 2 seconds to visit the page in the test. This is my base testClass:

use App\Models\User;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    protected $seed = true;

    protected function setUp(): void
    {
        ini_set('memory_limit', -1);

        parent::setUp(); 
    }
}

答案1

得分: 1

以下是翻译的内容:

这并不完全是您的解决方案,但我会稍微“美化和纠正”您的代码:

public function testUserListById()
{
    $user = User::factory()->create();

    $this->actingAs($user)
        ->json('get', route('users.list'))
        ->assertOk()
        ->decodeResponseJson();
}

在这里 decodeResponseJson() 如果无法解码将自动返回错误。请注意,它不是在断言是否有内容,而是在断言是否能够解码。

另外,我使用了 assertOk 而不是 assertStatus(200),有一些可用的方法来断言一些状态,一旦您习惯了它们,它们更“易读”,它们只是辅助方法。

为什么我不检查内容呢?因为您不应该计数或断言是否返回了内容,而应该断言确切返回了什么内容,否则测试只完成了一半,不正确,因为任何人都可以更改控制器的内容,您的测试仍然会通过,这样的测试如何可用?

非常个人的建议,请不要添加 ini_set('memory_limit', -1);,如果必须这样做,那么您没有正确地测试某些东西或者您的代码的某一部分绝对不高效(这是一个巨大的红旗),因此您应该查看哪个测试在消耗您的内存并修复它。这是微妙的代码气味/红旗。


现在,关于您的问题,我99%确定您有大量的迁移,或者一个迁移在做大量的工作,所以当您使用 RefreshDatabase 特性时,它只运行一次,然后在数据库中执行的任何操作只是一个事务,所以每个测试只有模式而没有内容(与为每个单独的测试迁移相比,这是高性能的)。

您如何知道这是否是问题?您可以添加简单的日志记录:

public function testUserListById()
{
    $start = now();

    $user = User::factory()->create();

    $this->actingAs($user)
        ->json('get', route('users.list'))
        ->assertStatus(200)
        ->decodeResponseJson();

    $end = now();

    dump($end->diffInMilliseconds($start));
}

您将看到一个类似于 1 // tests/Feature/ExampleTest.php:36 的数字,那是 dump,显示运行测试花费了1毫秒。如果测试非常快,那么迁移可能需要很长时间。

英文:

This is not exactly the solution for you, but I will "beautify and correct" your code a little bit:

public function testUserListById()
{
    $user = User::factory()->create();

    $this->actingAs($user)
        ->json('get', route('users.list'))
        ->assertOk()
        ->decodeResponseJson();
}

Here decodeResponseJson() will automatically give you an error back if it was not able to decode it. Have in mind that it is not asserting if it has content, just if it was able to decode it.

See also that I have used assertOk instead of assertStatus(200), there are available methods to assert some statuses, it is "easier" or more readable once you get used to them, they are just helpers.

Why am I not checking the content? Because you should not count or assert if you got content back, but exactly what content you expect back, else the test is half done, it is incorrect as anyone could change something from the controller and your test will still pass, how can a test like that be usable?

Super personal recommendation, do not add ini_set('memory_limit', -1);, if you have to do so, you are not correctly testing something or part of your code is absolutely not performant at all (a massive red flag), so you should see which test is destroying your memory and fix it. It is a subtle code smell/red flag.


Now, related to your issue, I am 99% sure you have a HUGE amount of migrations or one migration is doing a lot of work, so when you use RefreshDatabase trait, you can see it is only run once, then any action done in the database is just a transaction, so you only have the schema without content for each test (that is performant compared to migrating for every single test).

How can you know if this is the issue? You can add simple logging:

public function testUserListById()
{
    $start = now();

    $user = User::factory()->create();

    $this->actingAs($user)
        ->json('get', route('users.list'))
        ->assertStatus(200)
        ->decodeResponseJson();

    $end = now();

    dump($end->diffInMilliseconds($start));
}

You will see a number like this: 1 // tests/Feature/ExampleTest.php:36 that was the dump, showing it took 1 ms to run the test. If the test is super fast, then the migrations are taking a long time.

huangapple
  • 本文由 发表于 2023年6月13日 01:24:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76458976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定