2016-01-26 13 views
17

Gần đây, tôi gặp sự cố về ứng dụng trực tiếp. Tôi nhận ra rằng tôi đã có nhiều trường hợp ngoại lệ đồng thời hơn và khóa bằng cơ sở dữ liệu.Làm thế nào để kiểm tra đơn vị đồng thời đọc/ghi với PHPUnit?

Về cơ bản, tôi bắt đầu giao dịch yêu cầu SELECTINSERT trên cùng một bảng để cam kết. Nhưng vì tải trọng thực sự nặng, nên mỗi giao dịch sẽ khóa bảng, trong hầu hết các trường hợp nó quá nhanh, nó không gây ra bất kỳ vấn đề nào nhưng có một điểm mà ổ khóa bắt đầu chờ đợi ngày càng nhiều.

Tôi đã có thể khắc phục được vấn đề này bằng cách tinh chỉnh các truy vấn.

Mặc dù, bây giờ, tôi muốn viết một số thử nghiệm với PHPUnit để xác thực sửa lỗi của tôi và tránh bất kỳ hồi quy nào.

Tôi không thể tìm thấy bất kỳ tài liệu nào về cách thực hiện việc này.

Vì PHP không phải là đa luồng, tôi không có ý tưởng làm cách nào để có thể chạy các truy vấn đồng thời trong một thử nghiệm để xác thực.

Về cơ bản, tôi muốn có thể chạy nhiều cuộc gọi trong một lần kiểm tra để đảm bảo mọi thứ đều ổn.

Tôi biết mình có thể thử một số bài kiểm tra cấp cao bằng cách truy vấn trực tiếp máy chủ http và tải toàn bộ ứng dụng, nhưng vì vấn đề của tôi xuất phát từ một thư viện độc lập, tôi muốn thử nghiệm nó hơn.

Bất kỳ ý tưởng nào?

+0

Có cùng câu hỏi – XuDing

+0

Bạn không thể kiểm tra cách thông thường đồng thời. Những điều duy nhất bạn có thể làm là a) kiểm tra căng thẳng và b) thi hành các điều kiện mà tại đó bạn cho rằng sự bất thường sẽ xảy ra (nếu điều này là có thể). Về cơ bản, bạn không nên kiểm tra cơ sở dữ liệu, bạn nên đảm bảo rằng các giấy trắng nói rằng thuật toán của bạn an toàn và nếu bạn muốn cực kỳ chắc chắn, hãy thêm các bài kiểm tra căng thẳng cụ thể ở cấp độ kiểm tra cao nhất (ngoài ứng dụng). Để trả lời câu hỏi cụ thể, bạn luôn có thể sử dụng nhiều quy trình để thực hiện các hoạt động đồng thời, do đó việc sử dụng thủ công hoặc thư viện như kirsswallsmith/spork sẽ giúp ích. – Etki

Trả lời

5

Câu trả lời ngắn gọn là không có cách nào tốt để kiểm tra đọc/ghi đồng thời trên cơ sở dữ liệu thực với PHPUnit. Nó đơn giản không phải là công cụ thích hợp cho công việc đó.

Nhưng có một vài khía cạnh để giải pháp tốt để kiểm tra điều này. Đầu tiên, mã có thể được viết để xử lý mọi tình huống có thể xảy ra. Một hệ thống cơ sở dữ liệu như Postgres sẽ thất bại ngay lập tức trên các vấn đề về khóa và giao dịch. Để xử lý nó tao nhã tôi sử dụng mã mà trông giống như sau (pseudo-code, cũng sử dụng để trả lời another question):

begin transaction 
while not successful and count < 5 
    try 
     execute sql 
     commit 
    except 
     if error code is '40P01' or '55P03' 
      # Deadlock or lock not available 
      sleep a random time (200 ms to 1 sec) * number of retries 
     else if error code is '40001' or '25P02' 
      # "In failed sql transaction" or serialized transaction failure 
      rollback 
      sleep a random time (200 ms to 1 sec) * number of retries 
      begin transaction 
     else if error message is 'There is no active transaction' 
      sleep a random time (200 ms to 1 sec) * number of retries 
      begin transaction 
    increment count 

Sau đó tạo hai bộ xét nghiệm: một bộ nên xác nhận mã là xử lý các tình huống một cách chính xác (tức là kiểm tra đơn vị). Một loạt các bài kiểm tra khác dành cho môi trường (tức là các bài kiểm tra tích hợp/chức năng).

Unit Tests

Tôi thấy đây là một tình huống khó khăn để tái tạo trong một thử nghiệm PHPUnit kết nối với một cơ sở dữ liệu, và sử dụng một cơ sở dữ liệu thực sự là không thích hợp cho một thử nghiệm đơn vị thành sự thật. Thay vào đó, hãy tạo các lệnh PDO và các bài kiểm tra đơn vị để ném mọi loại ngoại lệ cơ sở dữ liệu. Điều này khẳng định mã đang làm việc như mong đợi, nhưng không kiểm tra đồng thời trên bất kỳ cơ sở dữ liệu thực, ví dụ .:

$iterationCount = 0; 
$db->runInTransaction(function() use (&$iterationCount) { 
    $iterationCount++; 
    if ($iterationCount === 1) { 
     $exception = new PDOExceptionStub('Deadlock'); 
     $exception->setCode('40P01'); 
     throw $exception; 
    } 
}); 

// First time fails, second time succeeds 
$this->assertEquals(2, $iterationCount, 'Expected 2 iterations of runInTransaction'); 

Viết một bộ đầy đủ các bài kiểm tra mà không kết nối với DB, nhưng khẳng định logic.

Integration Tests

Như các bạn đã thấy, PHPUnit chỉ đơn giản là không đúng công cụ để thực hiện một thử nghiệm tải.Nó không thích hợp cho bất cứ điều gì phức tạp hơn so với các bài kiểm tra đơn vị và tích hợp tuần tự. Bạn có thể chạy nhiều phiên bản của PHPUnit đồng thời để đặt thêm tải trên cơ sở dữ liệu. Tuy nhiên tôi thấy điều này vượt xa những gì nó đã có nghĩa là, cộng với nó không giúp bạn theo dõi cơ sở dữ liệu cho các vấn đề. Vì vậy, tôi không thấy cách nào xung quanh các bài kiểm tra cấp cao hơn mà bạn muốn tránh.

Nhưng thư viện của bạn có thể được kiểm tra mà không cần chạy ứng dụng hoàn chỉnh của bạn. Tôi sẽ tạo ra ứng dụng đơn giản nhất có thể chỉ để thử nghiệm nó. Nó có thể có một hoặc nhiều kịch bản lệnh CLI kết nối với cơ sở dữ liệu. Những kịch bản có thể được sinh ra nhiều lần để đặt tải trên cơ sở dữ liệu. Nếu nó giúp, điều này cũng cho phép bạn có một ứng dụng với mã bổ sung để theo dõi cơ sở dữ liệu.

+0

cảm ơn bạn đã giúp tôi rất nhiều. –

Các vấn đề liên quan