Là (cơ sở dữ liệu) kiểm tra tích hợp xấu?


120

Một số người duy trì rằng các bài kiểm tra tích hợp là tất cả các loại xấu và sai - mọi thứ phải được kiểm tra theo đơn vị, có nghĩa là bạn phải chế giễu các phụ thuộc; một lựa chọn mà, vì nhiều lý do, tôi không phải lúc nào cũng thích.

Tôi thấy rằng, trong một số trường hợp, một bài kiểm tra đơn vị đơn giản là không chứng minh được điều gì.

Hãy lấy cách triển khai kho lưu trữ (tầm thường, ngây thơ) sau đây (trong PHP) làm ví dụ:

class ProductRepository
{
    private $db;

    public function __construct(ConnectionInterface $db) {
        $this->db = $db;
    }

    public function findByKeyword($keyword) {
        // this might have a query builder, keyword processing, etc. - this is
        // a totally naive example just to illustrate the DB dependency, mkay?

        return $this->db->fetch("SELECT * FROM products p"
            . " WHERE p.name LIKE :keyword", ['keyword' => $keyword]);
    }
}

Giả sử tôi muốn chứng minh trong một thử nghiệm rằng kho lưu trữ này thực sự có thể tìm thấy các sản phẩm phù hợp với các từ khóa khác nhau.

Thiếu kiểm tra tích hợp với một đối tượng kết nối thực, làm sao tôi có thể biết rằng điều này thực sự tạo ra các truy vấn thực - và những truy vấn đó thực sự làm những gì tôi nghĩ họ làm?

Nếu tôi phải giả định đối tượng kết nối trong một bài kiểm tra đơn vị, tôi chỉ có thể chứng minh những thứ như "nó tạo ra truy vấn mong đợi" - nhưng điều đó không có nghĩa là nó thực sự sẽ hoạt động ... đó là, có thể nó đang tạo ra truy vấn Tôi đã mong đợi, nhưng có lẽ truy vấn đó không làm những gì tôi nghĩ.

Nói cách khác, tôi cảm thấy giống như một thử nghiệm đưa ra các xác nhận về truy vấn được tạo, về cơ bản là không có giá trị, bởi vì nó kiểm tra cách findByKeyword()thức phương thức được thực hiện , nhưng điều đó không chứng minh rằng nó thực sự hoạt động .

Vấn đề này không giới hạn ở kho lưu trữ hoặc tích hợp cơ sở dữ liệu - nó dường như được áp dụng trong rất nhiều trường hợp, trong đó việc đưa ra các xác nhận về việc sử dụng giả (test-double) chỉ chứng minh cách mọi thứ được thực hiện, chứ không phải là chúng sẽ xảy ra thực sự làm việc

Làm thế nào để bạn đối phó với các tình huống như thế này?

Các thử nghiệm tích hợp có thực sự "xấu" trong trường hợp như thế này không?

Tôi nhận thấy rằng nên kiểm tra một điều tốt hơn và tôi cũng hiểu tại sao kiểm thử tích hợp dẫn đến vô số đường dẫn mã, tất cả đều không thể được kiểm tra - nhưng trong trường hợp dịch vụ (chẳng hạn như kho lưu trữ) chỉ có mục đích là để tương tác với một thành phần khác, làm thế nào bạn thực sự có thể kiểm tra bất cứ điều gì mà không cần kiểm tra tích hợp?


5
Đọc agitar.com/doads/TheWayOfTestivus.pdf , đặc biệt là trang 6 "Bài kiểm tra quan trọng hơn bài học".
Doc Brown

2
@ user61852 nó nói "ngây thơ" trong mô tả, đúng không?
mindplay.dk

4
Làm thế nào đồng nghiệp của bạn sẽ hoàn toàn chắc chắn rằng cơ sở dữ liệu bị chế giễu của anh ta hoạt động như thật?
Thorbjørn Ravn Andersen

12
Bạn đang cố gắng để thực tế. Đồng nghiệp của bạn đang cố gắng tuân thủ các quy tắc. Luôn viết các bài kiểm tra tạo ra giá trị . Đừng lãng phí thời gian viết các bài kiểm tra sẽ không thể nhầm lẫn và đừng viết các bài kiểm tra không thực hiện một trong những điều sau đây: tăng xác suất mã của bạn là chính xác hoặc buộc bạn phải viết mã dễ bảo trì hơn.
jpmc26

3
@ mindplay.dk: câu quan trọng trong đoạn đó là "Nhưng đừng mắc kẹt với bất kỳ giáo điều nào. Viết bài kiểm tra cần phải viết. Đồng nghiệp của bạn dường như bị mắc kẹt trong giáo điều. Và bạn không cần ai đó giải thích cho bạn bài kiểm tra nào cần được viết trong ví dụ của bạn - bạn đã biết điều đó. Rõ ràng là để kiểm tra nếu cơ sở dữ liệu của bạn hiểu truy vấn, bạn phải chạy truy vấn đối với cơ sở dữ liệu thực - không giả mạo nào có thể cho bạn biết này.
Doc Brown

Câu trả lời:


129

Đồng nghiệp của bạn nói đúng rằng mọi thứ có thể được kiểm tra đơn vị nên được kiểm tra theo đơn vị, và bạn đúng rằng các bài kiểm tra đơn vị sẽ đưa bạn đến nay và không xa hơn, đặc biệt là khi viết các trình bao bọc đơn giản xung quanh các dịch vụ bên ngoài phức tạp.

Một cách suy nghĩ phổ biến về thử nghiệm là một kim tự tháp thử nghiệm . Đó là một khái niệm thường xuyên được kết nối với Agile và nhiều người đã viết về nó, bao gồm Martin Fowler (người gán cho Mike Cohn trong Succeeding with Agile ), Alistair ScottBlog thử nghiệm của Google .

        /\                           --------------
       /  \        UI / End-to-End    \          /
      /----\                           \--------/
     /      \     Integration/System    \      /
    /--------\                           \----/
   /          \          Unit             \  /
  --------------                           \/
  Pyramid (good)                   Ice cream cone (bad)

Ý tưởng là các thử nghiệm đơn vị chạy nhanh, linh hoạt là nền tảng của quá trình thử nghiệm, nên có nhiều thử nghiệm đơn vị tập trung hơn so với thử nghiệm hệ thống / tích hợp và thử nghiệm hệ thống / tích hợp nhiều hơn thử nghiệm đầu cuối. Khi bạn đến gần đỉnh hơn, các bài kiểm tra có xu hướng mất nhiều thời gian / tài nguyên hơn để chạy, có xu hướng dễ bị hỏng và dễ bong hơn và ít cụ thể hơn trong việc xác định hệ thống hoặc tệp nào bị hỏng ; một cách tự nhiên, tốt nhất là tránh "nặng đầu".

Đến thời điểm đó, các thử nghiệm tích hợp không tệ , nhưng sự phụ thuộc nặng nề vào chúng có thể cho thấy rằng bạn chưa thiết kế các thành phần riêng lẻ của mình để dễ kiểm tra. Hãy nhớ rằng, mục tiêu ở đây là kiểm tra xem thiết bị của bạn có hoạt động theo thông số kỹ thuật của nó hay không trong khi liên quan đến tối thiểu các hệ thống có thể phá vỡ khác : Bạn có thể muốn thử cơ sở dữ liệu trong bộ nhớ (mà tôi tính là một thử nghiệm thân thiện với kiểm tra đơn vị đôi cùng với giả ) để kiểm tra trường hợp cạnh nặng, ví dụ, sau đó viết một vài thử nghiệm tích hợp với công cụ cơ sở dữ liệu thực để xác định rằng các trường hợp chính hoạt động khi hệ thống được lắp ráp.


Như một lưu ý phụ, bạn đã đề cập rằng các giả lập bạn viết chỉ đơn giản là kiểm tra cách thực hiện một cái gì đó, chứ không phải là nó hoạt động . Đó là một cái gì đó của một antipotype: Một thử nghiệm là một tấm gương hoàn hảo cho việc thực hiện nó không thực sự thử nghiệm bất cứ điều gì cả. Thay vào đó, hãy kiểm tra rằng mọi lớp hoặc phương thức hoạt động theo thông số riêng của nó , ở bất kỳ mức độ trừu tượng hoặc chủ nghĩa hiện thực nào yêu cầu.


13
+1 cho "Một bài kiểm tra là một tấm gương hoàn hảo cho việc thực hiện nó không thực sự kiểm tra bất cứ điều gì cả." Tất cả quá phổ biến. Tôi gọi nó là Doppelganger Antipotype .
dodgethesteamler

6
Một trường phái phần mềm đối lập QA, phong trào thử nghiệm theo ngữ cảnh , một phần dành cho tranh luận rằng có tồn tại bất kỳ quy tắc chung hữu ích nào như Kim tự tháp Thử nghiệm. Cụ thể, các văn bản tinh dịch của phong trào đưa ra nhiều ví dụ trong đó các bài kiểm tra tích hợp có giá trị hơn nhiều so với các loại bài kiểm tra khác (vì chúng kiểm tra hệ thống theo ngữ cảnh, như một hệ thống ) ....
dodgethesteam điều khiển

7
... do đó, Fowler và cộng sự, cho rằng nên dành ít nỗ lực hơn cho các bài kiểm tra tích hợp và kiểm tra chấp nhận của người dùng vì chúng quá khó để viết theo cách mạnh mẽ và có thể duy trì được, thực sự chỉ cung cấp một lý do hậu thực tế cho lý do tại sao họ chưa tìm ra cách kiểm tra tốt ở cấp cao hơn.
dodgethesteamler

1
@dodgethesteamler Các cuộc thảo luận chuyên sâu về một "trường học đối lập" như thế có lẽ phù hợp nhất với câu trả lời của chính họ. Cá nhân, tôi thấy rằng Blog Thử nghiệm của Google thực hiện công việc khá tốt khi mô tả các ưu điểm của các thử nghiệm tự động nhanh, có phạm vi chặt chẽ cùng với các thử nghiệm trong ngữ cảnh hệ thống. Trong trường hợp bạn thấy nó không rõ ràng, tôi liệt kê kim tự tháp thử nghiệm ở đây là một mô hình hữu ích hoặc điểm khởi đầu, không phải là một cái cớ để ngừng suy nghĩ như một kỹ sư.
Jeff Bowman

1
Trình bày được đề xuất cao về phân cấp và tỷ lệ không đáng tin cậy đối với các bài kiểm tra tích hợp: vimeo.com/80533536 Giải thích rất rõ.
szalski

88

Một trong những đồng nghiệp của tôi khẳng định rằng các bài kiểm tra tích hợp là tất cả các loại xấu và sai - mọi thứ phải được kiểm tra theo đơn vị,

Điều đó giống như nói rằng kháng sinh là xấu - mọi thứ nên được chữa khỏi bằng vitamin.

Kiểm tra đơn vị không thể nắm bắt mọi thứ - họ chỉ kiểm tra cách một thành phần hoạt động trong môi trường được kiểm soát . Kiểm tra tích hợp xác minh rằng mọi thứ hoạt động cùng nhau , khó thực hiện hơn nhưng cuối cùng có ý nghĩa hơn.

Một quy trình kiểm tra toàn diện, tốt, sử dụng cả hai loại thử nghiệm - thử nghiệm đơn vị để xác minh quy tắc kinh doanh và những thứ khác có thể được thử nghiệm độc lập và thử nghiệm tích hợp để đảm bảo mọi thứ hoạt động cùng nhau.

Thiếu kiểm tra tích hợp với một đối tượng kết nối thực, làm sao tôi có thể biết rằng điều này thực sự tạo ra các truy vấn thực - và những truy vấn đó thực sự làm những gì tôi nghĩ họ làm?

Bạn có thể đơn vị kiểm tra nó ở cấp cơ sở dữ liệu . Chạy truy vấn với các tham số khác nhau và xem nếu bạn nhận được kết quả mà bạn mong đợi. Cấp nó có nghĩa là sao chép / dán bất kỳ thay đổi nào trở lại mã "thật". nhưng nó không cho phép bạn kiểm tra độc lập truy vấn của bất kỳ phụ thuộc khác.


Bạn sẽ không kiểm tra liệu cơ sở dữ liệu có chứa dữ liệu nhất định không?
Tulains Córdova

Có thể - nhưng bạn cũng có thể kiểm tra xem các bộ lọc, tham gia phức tạp, v.v. của bạn có hoạt động không. Truy vấn mẫu có thể không phải là ứng cử viên tốt nhất cho "bài kiểm tra đơn vị" nhưng một truy vấn có các phép nối và / hoặc tập hợp phức tạp có thể.
D Stanley

Có - ví dụ tôi đã sử dụng, như đã chỉ ra, là tầm thường; một kho lưu trữ thực sự có thể có tất cả các cách tùy chọn tìm kiếm và sắp xếp phức tạp, ví dụ như sử dụng trình tạo truy vấn, v.v.
mindplay.dk

2
Câu trả lời tốt, nhưng tôi sẽ thêm rằng DB nên có trong bộ nhớ, để đảm bảo rằng các bài kiểm tra đơn vị nhanh.
BЈовић

3
@ BЈовић: Thật không may, điều đó có thể không phải lúc nào cũng có thể xảy ra, vì không may là không có hai DB tương thích ngoài kia và không phải tất cả chúng đều hoạt động trong bộ nhớ. Ngoài ra còn có vấn đề cấp phép cho các DB thương mại (bạn có thể không có giấy phép để chạy nó trên bất kỳ máy nào), ...
Matthieu M.

17

Các bài kiểm tra đơn vị không nắm bắt được tất cả các khuyết tật. Nhưng chúng rẻ hơn để thiết lập và (chạy lại) so với các loại thử nghiệm khác. Các thử nghiệm đơn vị được chứng minh bằng sự kết hợp của giá trị vừa phải và chi phí thấp đến trung bình.

Đây là bảng hiển thị tỷ lệ phát hiện lỗi cho các loại thử nghiệm khác nhau.

nhập mô tả hình ảnh ở đây

nguồn: p.470 trong Mã hoàn thành 2 của McConnell


5
Dữ liệu đó được thu thập vào năm 1986 . Đó là ba mươi năm trước . Các bài kiểm tra đơn vị năm 1986 không giống như ngày nay. Tôi sẽ hoài nghi về dữ liệu này. Chưa kể, các bài kiểm tra đơn vị phát hiện ra lỗi trước khi nó được cam kết , vì vậy nghi ngờ rằng chúng sẽ được báo cáo.
RubberDuck

3
@RubberDuck Biểu đồ này là từ một cuốn sách năm 2006 và nó dựa trên dữ liệu từ năm 1986, 1996, 2002 (nếu bạn xem xét kỹ). Tôi đã không xem xét các giao thức thu thập dữ liệu trong các nguồn, tôi không thể nói khi nào chúng bắt đầu theo dõi một khiếm khuyết và cách nó được báo cáo. Biểu đồ này có thể là một phần lỗi thời? Nó có thể. Tháng 12 năm ngoái tôi đã có mặt tại một hội thảo, và người hướng dẫn đã đề cập rằng các bài kiểm tra tích hợp tìm thấy nhiều lỗi hơn các bài kiểm tra đơn vị (theo hệ số 2, iirc). Biểu đồ này nói rằng chúng giống nhau.
Nick Alexeev

13

Không, họ không tệ. Hy vọng, một người nên có bài kiểm tra đơn vị và tích hợp. Chúng được sử dụng và chạy ở các giai đoạn khác nhau trong chu kỳ phát triển.

Bài kiểm tra đơn vị

Các thử nghiệm đơn vị nên được chạy trên máy chủ xây dựng và cục bộ, sau khi mã được biên dịch. Nếu bất kỳ kiểm thử đơn vị nào thất bại, người ta sẽ thất bại trong quá trình xây dựng hoặc không cam kết cập nhật mã cho đến khi các thử nghiệm được khắc phục. Lý do tại sao chúng tôi muốn các thử nghiệm đơn vị bị cô lập là vì chúng tôi muốn máy chủ xây dựng có thể chạy tất cả các thử nghiệm mà không cần tất cả các phụ thuộc. Sau đó, chúng tôi có thể chạy bản dựng mà không cần tất cả các phụ thuộc phức tạp cần thiết và có rất nhiều bài kiểm tra chạy rất nhanh.

Vì vậy, đối với một cơ sở dữ liệu, người ta nên có một cái gì đó như:

IRespository

List<Product> GetProducts<String Size, String Color);

Bây giờ, việc triển khai thực sự của IRep repository sẽ đến cơ sở dữ liệu để lấy các sản phẩm, nhưng để thử nghiệm đơn vị, người ta có thể giả định IRep repository với một giả mạo để chạy tất cả các thử nghiệm khi cần mà không cần cơ sở dữ liệu Actaul vì chúng ta có thể mô phỏng tất cả các loại danh sách sản phẩm được trả về từ ví dụ giả và kiểm tra bất kỳ logic nghiệp vụ nào với dữ liệu bị giả định.

Kiểm tra tích hợp

Kiểm tra tích hợp thường là kiểm tra vượt biên. Chúng tôi muốn chạy các thử nghiệm này trên máy chủ triển khai (môi trường thực), hộp cát hoặc thậm chí cục bộ (chỉ vào hộp cát). Họ không chạy trên máy chủ xây dựng. Sau khi phần mềm đã được triển khai vào môi trường, thông thường những phần mềm này sẽ được chạy dưới dạng hoạt động triển khai bài. Chúng có thể được tự động thông qua các tiện ích dòng lệnh. Ví dụ: chúng ta có thể chạy nUnit từ dòng lệnh nếu chúng ta phân loại tất cả các bài kiểm tra tích hợp mà chúng ta muốn gọi. Chúng thực sự gọi kho lưu trữ thực với cuộc gọi cơ sở dữ liệu thực. Những loại xét nghiệm này giúp với:

  • Môi trường Ổn định Sức khỏe Sẵn sàng
  • Kiểm tra thực tế

Các thử nghiệm này đôi khi khó chạy hơn vì chúng tôi có thể cần phải thiết lập và / hoặc phá bỏ. Xem xét thêm một sản phẩm. Chúng tôi có thể muốn thêm sản phẩm, truy vấn nó để xem nếu nó đã được thêm, và sau khi chúng tôi hoàn thành, hãy xóa nó. Chúng tôi không muốn thêm 100 hoặc 1000 sản phẩm "tích hợp", do đó cần phải thiết lập thêm.

Các thử nghiệm tích hợp có thể chứng minh là khá có giá trị để xác nhận một môi trường và đảm bảo thực tế hoạt động.

Một nên có cả hai.

  • Chạy các bài kiểm tra đơn vị cho mọi bản dựng.
  • Chạy các bài kiểm tra tích hợp cho mọi triển khai.

Tôi sẽ khuyên bạn nên chạy thử nghiệm tích hợp cho mọi bản dựng, thay vì phải cam kết và thúc đẩy. Phụ thuộc vào thời gian họ mất bao lâu, nhưng đó cũng là một ý tưởng tốt để giữ cho họ nhanh vì nhiều lý do.
artbristol

@ArtBristol - Thông thường máy chủ xây dựng của chúng tôi không có cấu hình phụ thuộc môi trường đầy đủ, vì vậy chúng tôi không thể chạy thử nghiệm tích hợp ở đó. Nhưng nếu một người có thể chạy các bài kiểm tra tích hợp ở đó, hãy thực hiện nó. Chúng tôi có một hộp cát triển khai được thiết lập sau bản dựng mà chúng tôi sử dụng để kiểm tra tích hợp để xác minh việc triển khai. Nhưng mỗi tình huống là khác nhau.
Jon Raynor

11

Kiểm tra tích hợp cơ sở dữ liệu không phải là xấu. Thậm chí nhiều hơn, chúng là cần thiết.

Bạn có thể có ứng dụng của bạn được chia thành các lớp, và đó là một điều tốt. Bạn có thể kiểm tra từng lớp một cách cô lập bằng cách chế nhạo các lớp lân cận, và đó cũng là một điều tốt. Nhưng cho dù bạn tạo ra bao nhiêu lớp trừu tượng, đến một lúc nào đó cũng phải có lớp thực hiện công việc bẩn thỉu - thực sự nói chuyện với cơ sở dữ liệu. Trừ khi bạn kiểm tra nó, bạn không kiểm tra gì cả. Nếu bạn kiểm tra lớp n bằng cách chế nhạo lớp n-1, bạn đang đánh giá giả định rằng lớp n hoạt động với điều kiện lớp n-1 hoạt động. Để làm việc này, bằng cách nào đó bạn phải chứng minh rằng lớp 0 hoạt động.

Mặc dù về lý thuyết, bạn có thể đơn vị kiểm tra cơ sở dữ liệu, bằng cách phân tích và giải thích SQL được tạo, việc tạo cơ sở dữ liệu kiểm tra một cách dễ dàng và đáng tin cậy hơn rất nhiều.

Phần kết luận

Độ tin cậy được định vị từ đơn vị kiểm tra Kho lưu trữ trừu tượng của bạn , Ethereal Object- Relative -Mapper , Generic Active Record , Theoretic Persistence , khi cuối cùng SQL được tạo của bạn có lỗi cú pháp?


Tôi đã nghĩ đến việc thêm một câu trả lời tương tự như của bạn nhưng bạn đã nói nó tốt hơn! Theo kinh nghiệm của tôi, có một số thử nghiệm trên lớp nhận và lưu trữ dữ liệu đã giúp tôi tiết kiệm rất nhiều đau buồn.
Daniel Hollinrake 4/11/2015

Kiểm tra tích hợp cơ sở dữ liệu là xấu mặc dù. Bạn có cơ sở dữ liệu có sẵn trong dòng ci / cd của mình không? Điều đó có vẻ khá phức tạp với tôi. Sẽ dễ dàng hơn nhiều để giả định các công cụ cơ sở dữ liệu và xây dựng một lớp trừu tượng để sử dụng nó. Không chỉ là một giải pháp thanh lịch hơn nhiều, nó còn nhanh như có thể. Kiểm tra đơn vị cần phải nhanh chóng. Việc kiểm tra cơ sở dữ liệu của bạn sẽ làm chậm đáng kể mức độ khó tin của bạn đến mức không thể chấp nhận được. Unittests không nên mất> 10 phút để hoàn thành, ngay cả khi bạn có hàng ngàn người.
David

@David Bạn có sẵn một cơ sở dữ liệu trong dòng ci / cd của mình không? Chắc chắn, đó là tính năng khá chuẩn . BTW, tôi không ủng hộ các thử nghiệm tích hợp thay vì thử nghiệm đơn vị - Tôi ủng hộ các thử nghiệm tích hợp kết hợp với thử nghiệm đơn vị. Kiểm tra đơn vị nhanh là rất cần thiết, nhưng cơ sở dữ liệu quá phức tạp để dựa vào kiểm tra đơn vị với các tương tác giả.
el.pescado

@ el.pescado Tôi phải không đồng ý. Nếu giao tiếp cơ sở dữ liệu của bạn đứng sau một lớp trừu tượng, nó thực sự dễ dàng để chế giễu. Bạn chỉ có thể quyết định đối tượng nào để trở lại. Ngoài ra, thực tế là một cái gì đó là tiêu chuẩn không làm cho nó một điều tốt.
David

@David Tôi nghĩ nó phụ thuộc vào cách bạn tiếp cận cơ sở dữ liệu. Là chi tiết thực hiện hoặc phần quan trọng của hệ thống ? (Tôi nghiêng về phía sau) . Nếu bạn coi cơ sở dữ liệu là một kho lưu trữ dữ liệu câm, thì có, bạn có thể làm mà không cần kiểm tra tích hợp. Tuy nhiên, nếu có bất kỳ logic nào trong cơ sở dữ liệu - các ràng buộc, kích hoạt, khóa ngoại, giao dịch hoặc lớp dữ liệu của bạn sử dụng SQL tùy chỉnh thay vì các phương thức ORM đơn giản, tôi cảm thấy các bài kiểm tra đơn vị sẽ không đủ.
el.pescado

6

Bạn cần cả hai.

Trong ví dụ của bạn nếu bạn đang kiểm tra cơ sở dữ liệu trong một điều kiện nhất định, khi findByKeywordphương thức được chạy, bạn sẽ lấy lại dữ liệu mà bạn mong đợi đây là một thử nghiệm tích hợp tốt.

Trong bất kỳ mã nào khác đang sử dụng findByKeywordphương thức đó mà bạn muốn kiểm soát những gì đang được cung cấp cho bài kiểm tra, do đó bạn có thể trả về null hoặc từ đúng cho bài kiểm tra của mình hoặc bất cứ điều gì sau đó bạn giả định phụ thuộc cơ sở dữ liệu để bạn biết chính xác bài kiểm tra của mình nhận (và bạn mất chi phí kết nối với cơ sở dữ liệu và đảm bảo dữ liệu trong đó là chính xác)


6

Tác giả của bài viết blog mà bạn đề cập chủ yếu quan tâm đến sự phức tạp tiềm tàng có thể phát sinh từ các bài kiểm tra tích hợp (mặc dù nó được viết theo một cách rất quan tâm và phân loại). Tuy nhiên, các thử nghiệm tích hợp không nhất thiết là xấu và một số thử nghiệm thực sự hữu ích hơn các thử nghiệm đơn vị thuần túy. Nó thực sự phụ thuộc vào ngữ cảnh của ứng dụng của bạn và những gì bạn đang cố gắng kiểm tra.

Nhiều ứng dụng ngày nay đơn giản là không hoạt động nếu máy chủ cơ sở dữ liệu của chúng bị hỏng. Ít nhất, hãy nghĩ về nó trong bối cảnh tính năng bạn đang thử nghiệm.

Một mặt, nếu những gì bạn đang thử nghiệm không phụ thuộc hoặc hoàn toàn không phụ thuộc vào cơ sở dữ liệu, thì hãy viết thử nghiệm của bạn theo cách mà nó thậm chí không thử sử dụng cơ sở dữ liệu (chỉ cung cấp dữ liệu giả theo yêu cầu). Ví dụ: nếu bạn đang thử kiểm tra một số logic xác thực khi phục vụ một trang web (ví dụ), thì có lẽ nên tách rời khỏi DB hoàn toàn (giả sử bạn không dựa vào DB để xác thực hoặc điều đó bạn có thể chế giễu nó một cách hợp lý dễ dàng).

Mặt khác, nếu đó là một tính năng phụ thuộc trực tiếp vào cơ sở dữ liệu của bạn và hoàn toàn không hoạt động trong môi trường thực thì cơ sở dữ liệu sẽ không có sẵn, sau đó chế nhạo DB làm gì trong mã máy khách DB của bạn (tức là lớp sử dụng lớp đó DB) không nhất thiết phải có ý nghĩa.

Ví dụ: nếu bạn biết rằng ứng dụng của bạn sẽ dựa vào cơ sở dữ liệu (và có thể trên một hệ thống cơ sở dữ liệu cụ thể), việc chế giễu hành vi cơ sở dữ liệu vì lợi ích của nó thường sẽ gây lãng phí thời gian. Các công cụ cơ sở dữ liệu (đặc biệt là RDBMS) là các hệ thống phức tạp. Một vài dòng SQL thực sự có thể thực hiện rất nhiều công việc, điều này rất khó mô phỏng (thực tế, nếu truy vấn SQL của bạn dài vài dòng, rất có thể bạn sẽ cần nhiều dòng Java / PHP / C # / Python hơn mã để tạo ra cùng một kết quả trong nội bộ): sao chép logic mà bạn đã triển khai trong DB không có ý nghĩa gì và việc kiểm tra mã kiểm tra đó sau đó sẽ trở thành một vấn đề.

Tôi không nhất thiết coi đây là một vấn đề của bài kiểm tra đơn vị so với bài kiểm tra tích hợp , mà là nhìn vào phạm vi của những gì đang được kiểm tra. Các vấn đề chung của kiểm thử đơn vị và tích hợp vẫn còn: bạn cần một bộ dữ liệu kiểm thử và các trường hợp kiểm thử thực tế hợp lý, nhưng một cái gì đó cũng đủ nhỏ để các bài kiểm tra được thực hiện nhanh chóng.

Thời gian để thiết lập lại cơ sở dữ liệu và phục hồi dữ liệu thử nghiệm là một khía cạnh cần xem xét; bạn thường đánh giá điều này theo thời gian cần thiết để viết mã giả đó (cuối cùng bạn sẽ phải duy trì).

Một điểm khác cần xem xét là mức độ phụ thuộc mà ứng dụng của bạn có với cơ sở dữ liệu.

  • Nếu ứng dụng của bạn chỉ đơn giản tuân theo mô hình CRUD, trong đó bạn có một lớp trừu tượng cho phép bạn trao đổi giữa bất kỳ RDBMS nào bằng cách cài đặt cấu hình đơn giản, rất có thể bạn sẽ có thể làm việc với một hệ thống giả khá dễ dàng (có thể làm mờ dòng giữa đơn vị và thử nghiệm tích hợp sử dụng RDBMS trong bộ nhớ).
  • Nếu ứng dụng của bạn sử dụng logic phức tạp hơn, một cái gì đó sẽ dành riêng cho một trong SQL Server, MySQL, PostgreQuery (chẳng hạn), thì nói chung sẽ có ý nghĩa hơn khi có một bài kiểm tra sử dụng hệ thống cụ thể đó.

"Nhiều ứng dụng ngày nay đơn giản là không hoạt động nếu máy chủ cơ sở dữ liệu của chúng bị hỏng" - đó thực sự là điểm quan trọng!
el.pescado

Giải thích tốt về các giới hạn của các giả lập phức tạp, như sử dụng ngôn ngữ khác để giả định SQL. Khi mã kiểm tra trở nên phức tạp đến mức có vẻ như nó cần phải được kiểm tra, đó là mùi QA.
dodgethesteamler

1

Bạn có quyền nghĩ rằng một bài kiểm tra đơn vị như vậy là không đầy đủ. Sự không hoàn hảo là trong giao diện cơ sở dữ liệu bị chế giễu. Những kỳ vọng hay khẳng định ngây thơ như vậy là không đầy đủ.

Để hoàn thành, bạn phải dành đủ thời gian và tài nguyên để viết hoặc tích hợp một công cụ quy tắc SQL để đảm bảo rằng câu lệnh SQL được phát ra bởi chủ đề được kiểm tra, sẽ dẫn đến các hoạt động dự kiến.

Tuy nhiên, sự thay thế / đồng hành thường bị lãng quên và hơi đắt tiền để chế giễu là "ảo hóa" .

Bạn có thể quay một cá thể DB tạm thời, trong bộ nhớ nhưng "thực" để kiểm tra một chức năng không? Đúng ? Ở đó, bạn có một bài kiểm tra tốt hơn, bài kiểm tra dữ liệu thực tế được lưu và truy xuất.

Bây giờ, người ta có thể nói, bạn đã biến một bài kiểm tra đơn vị thành một bài kiểm tra tích hợp. Có nhiều quan điểm khác nhau về nơi vẽ đường thẳng để phân loại giữa kiểm tra đơn vị và kiểm tra tích hợp. IMHO, "đơn vị" là một định nghĩa tùy ý và phù hợp với nhu cầu của bạn.


1
điều này dường như chỉ lặp lại các điểm được thực hiện và giải thích trong câu trả lời trước đó đã được đăng cách đây vài giờ
gnat

0

Unit TestsIntegration Teststrực giao với nhau. Họ cung cấp một cái nhìn khác về ứng dụng bạn đang xây dựng. Thông thường bạn muốn cả hai . Nhưng thời điểm khác nhau, khi bạn muốn thử nghiệm loại nào.

Thường xuyên nhất bạn muốn Unit Tests. Các bài kiểm tra đơn vị tập trung vào một phần nhỏ của mã đang được kiểm tra - chính xác cái được gọi là a unitđược để lại cho người đọc. Nhưng mục đích của te rất đơn giản: nhận phản hồi nhanh về thời điểmnơi mã của bạn bị hỏng . Điều đó nói rằng, cần phải rõ ràng, rằng các cuộc gọi đến một DB thực tế là một nono .

Mặt khác, có những thứ, chỉ có thể được kiểm tra đơn vị trong điều kiện cứng mà không có cơ sở dữ liệu. Có lẽ có một điều kiện chủng tộc trong mã của bạn và một cuộc gọi tới DB sẽ vi phạm unique constraintđiều mà chỉ có thể được ném nếu bạn thực sự sử dụng hệ thống của mình. Nhưng những loại thử nghiệm đắt tiền mà bạn không thể (và không muốn) chạy chúng thường xuyên như vậy unit tests.


0

Trong thế giới .Net, tôi có thói quen tạo một dự án thử nghiệm và tạo các thử nghiệm như một phương pháp mã hóa / gỡ lỗi / thử nghiệm khứ hồi trừ giao diện người dùng. Đây là một cách hiệu quả để tôi phát triển. Tôi không quan tâm đến việc chạy tất cả các thử nghiệm cho mọi bản dựng (vì nó làm chậm dòng công việc phát triển của tôi), nhưng tôi hiểu tính hữu ích của việc này đối với một nhóm lớn hơn. Tuy nhiên, bạn có thể đưa ra một quy tắc rằng trước khi thực hiện mã, tất cả các kiểm tra nên được chạy và vượt qua (nếu mất nhiều thời gian hơn để kiểm tra chạy vì cơ sở dữ liệu thực sự bị tấn công).

Việc loại bỏ lớp truy cập dữ liệu (DAO) và không thực sự đánh vào cơ sở dữ liệu, không những không cho phép tôi viết mã theo cách tôi muốn và đã quen, nhưng nó bỏ lỡ một phần lớn cơ sở mã thực tế. Nếu bạn không thực sự kiểm tra lớp truy cập dữ liệu và cơ sở dữ liệu và chỉ giả vờ, sau đó dành nhiều thời gian để chế nhạo mọi thứ, tôi không nắm bắt được tính hữu ích của phương pháp này để thực sự kiểm tra mã của tôi. Tôi đang thử nghiệm một mảnh nhỏ thay vì một cái lớn hơn với một thử nghiệm. Tôi hiểu cách tiếp cận của tôi có thể giống với các bài kiểm tra tích hợp hơn, nhưng có vẻ như bài kiểm tra đơn vị với bản giả là một sự lãng phí thời gian nếu bạn thực sự chỉ viết bài kiểm tra tích hợp một lần và trước tiên. Đó cũng là một cách tốt để phát triển và gỡ lỗi.

Trên thực tế, trong một thời gian bây giờ tôi đã biết về TDD và Thiết kế hướng hành vi (BDD) và suy nghĩ về cách sử dụng nó, nhưng thật khó để thêm các bài kiểm tra đơn vị hồi tố. Có lẽ tôi đã sai, nhưng viết một bài kiểm tra bao gồm nhiều mã từ đầu đến cuối với cơ sở dữ liệu đi kèm, có vẻ như là một bài kiểm tra có mức độ ưu tiên cao hơn và đầy đủ hơn để viết bao gồm nhiều mã hơn và là cách hiệu quả hơn để viết bài kiểm tra.

Trên thực tế, tôi nghĩ rằng một cái gì đó giống như Thiết kế hướng hành vi (BDD) cố gắng kiểm tra từ đầu đến cuối bằng ngôn ngữ cụ thể của miền (DSL) sẽ là cách tốt nhất. Chúng tôi có SpecFlow trong thế giới .Net, nhưng nó bắt đầu như một nguồn mở với Cucumber.

https://cucumber.io/

Tôi thực sự không ấn tượng với sự hữu ích thực sự của bài kiểm tra mà tôi đã viết để chế nhạo lớp truy cập dữ liệu và không nhấn vào cơ sở dữ liệu. Đối tượng trả về không đánh vào cơ sở dữ liệu và không được điền dữ liệu. Đó là một vật hoàn toàn trống rỗng mà tôi phải chế nhạo một cách không tự nhiên. Tôi chỉ nghĩ rằng đó là một sự lãng phí thời gian.

Theo Stack Overflow, chế độ chế nhạo được sử dụng khi các đối tượng thực không thực tế để kết hợp vào kiểm tra đơn vị.

https://stackoverflow.com/questions/2665812/what-is-mocking

"Mocking chủ yếu được sử dụng trong thử nghiệm đơn vị. Một đối tượng được thử nghiệm có thể có sự phụ thuộc vào các đối tượng (phức tạp) khác. Để cô lập hành vi của đối tượng bạn muốn kiểm tra, bạn thay thế các đối tượng khác bằng giả lập mô phỏng hành vi của các đối tượng thực. Điều này rất hữu ích nếu các đối tượng thực tế không thực tế để kết hợp vào bài kiểm tra đơn vị. "

Lập luận của tôi là nếu tôi mã hóa mọi thứ từ đầu đến cuối (giao diện người dùng web đến lớp doanh nghiệp sang lớp truy cập dữ liệu vào cơ sở dữ liệu, chuyến đi khứ hồi), trước khi tôi kiểm tra bất cứ điều gì với tư cách là nhà phát triển, tôi sẽ kiểm tra luồng hành trình khứ hồi này. Nếu tôi cắt bỏ UI và gỡ lỗi và kiểm tra luồng này bắt đầu từ một thử nghiệm, tôi sẽ kiểm tra mọi thứ thiếu UI và trả về chính xác những gì UI mong đợi. Tất cả những gì tôi còn lại là gửi UI những gì nó muốn.

Tôi có một bài kiểm tra đầy đủ hơn, đó là một phần trong quy trình phát triển tự nhiên của tôi. Đối với tôi, đó phải là thử nghiệm ưu tiên cao nhất bao gồm thử nghiệm kết thúc đặc tả người dùng thực tế để kết thúc càng nhiều càng tốt. Nếu tôi không bao giờ tạo bất kỳ thử nghiệm chi tiết nào khác, ít nhất tôi có một thử nghiệm hoàn chỉnh hơn này chứng minh chức năng mong muốn của tôi hoạt động.

Một người đồng sáng lập Stack Exchange không bị thuyết phục về lợi ích của việc có phạm vi kiểm tra đơn vị 100%. Tôi cũng không. Tôi sẽ thực hiện một "bài kiểm tra tích hợp" hoàn chỉnh hơn, đánh vào cơ sở dữ liệu bằng cách duy trì một loạt các giả lập cơ sở dữ liệu bất kỳ ngày nào.

https://www.joelonsoftware.com/2009/01/31/from-podcast-38/


rõ ràng là bạn không hiểu sự khác biệt giữa các bài kiểm tra đơn vị và tích hợp
BЈовић

Tôi nghĩ rằng nó phụ thuộc vào dự án. Trên các dự án nhỏ hơn với ít tài nguyên hơn, nơi nhà phát triển chịu trách nhiệm tổng thể về kiểm tra và kiểm tra hồi quy vì thiếu người kiểm tra và giữ tài liệu đồng bộ với mã, nếu tôi dành thời gian để viết bài kiểm tra, thì đó sẽ là những bài kiểm tra cung cấp cho tôi nhiều bang nhất cho buck của tôi. Tôi muốn giết càng nhiều chim bằng một hòn đá càng tốt. Nếu hầu hết logic và lỗi của tôi đến từ các quy trình được lưu trữ cơ sở dữ liệu đang tạo báo cáo hoặc từ JavaScript giao diện người dùng, việc có phạm vi kiểm tra đơn vị đầy đủ trong tầng trung gian sẽ không giúp ích nhiều.
dùng3198764

-1

Các phụ thuộc bên ngoài nên bị chế giễu vì bạn không thể kiểm soát chúng (chúng có thể vượt qua trong giai đoạn thử nghiệm tích hợp nhưng không thành công trong sản xuất). Ổ đĩa có thể thất bại, kết nối cơ sở dữ liệu có thể không thành công vì bất kỳ lý do nào, có thể có sự cố mạng, v.v. Việc kiểm tra tích hợp không mang lại sự tự tin nào thêm vì tất cả đều là vấn đề có thể xảy ra khi chạy.

Với các thử nghiệm đơn vị thực sự, bạn đang thử nghiệm trong giới hạn của hộp cát và nó sẽ rõ ràng. Nếu một nhà phát triển đã viết một truy vấn SQL không thành công trong QA / PROD, điều đó có nghĩa là họ thậm chí đã không kiểm tra nó một lần trước thời điểm đó.


+1 cho "bạn không thể kiểm soát chúng (chúng có thể vượt qua trong giai đoạn thử nghiệm tích hợp nhưng không thành công trong sản xuất)" .
Tulains Córdova

Bạn có thể kiểm soát chúng đến mức độ hài lòng.
el.pescado

Tôi nhận được quan điểm của bạn, nhưng tôi nghĩ điều này đã từng đúng hơn ngày nay? Với tự động hóa và các công cụ (như Docker), bạn thực sự có thể sao chép và lặp lại việc thiết lập tất cả các phụ thuộc nhị phân / máy chủ của mình một cách chính xác và đáng tin cậy cho các bộ kiểm thử tích hợp. Tất nhiên, có, phần cứng vật lý (và dịch vụ của bên thứ ba, v.v.) có thể thất bại.
mindplay.dk

5
Tôi hoàn toàn không đồng ý. Bạn nên viết (bổ sung) các bài kiểm tra tích hợp vì các phụ thuộc mở rộng có thể thất bại. Các phụ thuộc bên ngoài có thể có những đặc điểm riêng, rất có thể bạn sẽ bỏ lỡ khi bạn chế giễu mọi thứ.
Paul Kertscher

1
@PaulK vẫn đang cân nhắc câu trả lời nào được đánh dấu là chấp nhận, nhưng tôi đang nghiêng về cùng một kết luận.
mindplay.dk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.